feat(runtime-node): error-linked trace retention + Docker Desktop quickstart fixes - #14
Conversation
…nstrument.cjs placement Two out-of-box quickstart fixes: - Pin the ClickHouse container healthcheck to 127.0.0.1 instead of localhost. Inside the container, localhost resolves to ::1, but the image's IPv6 bind (listen_host ::) can fail silently (listen_try 1) — reproduced on Docker Desktop for Mac, where only 0.0.0.0 ends up listening. busybox wget then gets ECONNREFUSED on every probe, the container stays unhealthy forever, and depends_on never releases the ingester. 127.0.0.1 targets the one listener the image reliably binds. Applied to the local compose file and the single-server deploy. - State explicitly that instrumentation happens in the user's own app: the guide flowed from `cd autter-runtime` straight into `npm install @autter/runtime-node` + "create instrument.cjs" without saying those steps belong in the application being instrumented, not the cloned ingester repo. Generated-By: PostHog Desktop Task-Id: 48cd4f81-8933-4d3d-b05a-1242ff7c25d3
…e behind every error Errors export at 100% (always-on tracer) while traces are head-sampled at ~1%, so the trace that explains a retained error was almost always gone — an issue's occurrence pointed at a trace that had one lonely error span. Retention is tail-based and entirely in-process, default on (retainTracesOnError): - RecordUnsampledSampler upgrades NOT_RECORD decisions to RECORD, so head-unsampled traces still materialise in-process. The W3C traceparent stays unsampled, so downstream propagation is unchanged. - ErrorTraceRetentionProcessor buffers finished-but-unsampled spans per trace and promotes the whole trace to export the moment it shows an error: an ERROR-status span (5xx included), an exception event, a captureException, or an error/fatal captureMessage inside it. Rescued spans get the sampled flag and ride their own batch processor on the errors' 2 s flush cadence. - Bounded by construction: 256 spans/trace, 5 000 spans total (oldest whole trace evicted first), buffers dropped as soon as the local root ends healthy, 30 s TTL sweep on an unref'd timer. Overflow degrades to plain head sampling; nothing ever blocks. - Rescued spans carry autter.tail_retained, and the ingester keeps such spans out of span-fed usage rollups — erroring requests are already counted by the metrics pipeline at 100%, so folding near-100% of their server spans in would have double-counted erroring routes. This also surfaces 5xx-derived issues reliably: an unhandled throw that a framework converts to a 500 previously only became an issue if the 1% lottery kept its span; the ERROR-status server span now always exports. No ingester schema changes — rescued spans land in runtime_spans under its existing TTL. Docs updated (runtime-node README, getting-started, integrations sampling guidance, design principles). Generated-By: PostHog Desktop Task-Id: 48cd4f81-8933-4d3d-b05a-1242ff7c25d3
There was a problem hiding this comment.
🔴 Autter review in progress — running security, correctness & dependency checks on this PR. Follow live step-by-step progress on the autter/review-gate check in the merge box. Merge is blocked until the gate completes; Autter approves automatically when the review comes back clean, and releases this hold with a neutral review when it finds non-blocking issues.
| function withSampledFlag(span: ReadableSpan): ReadableSpan { | ||
| const spanContext = { | ||
| ...span.spanContext(), | ||
| traceFlags: span.spanContext().traceFlags | TraceFlags.SAMPLED, |
There was a problem hiding this comment.
🟡 [ai] Simplifiable code — Risk: 10/100
withSampledFlag calls span.spanContext twice while constructing the same context. This affects the initAutterServer error-retention export path, including traces rescued by captureException and captureMessage. Read the original context once and reuse it. Blast radius — if this hygiene issue is left in it makes the downstream usage that depends on this file harder to change safely: functions AutterServerOptions, AutterSeverity, LlmUsage, initAutterServer, autterLlmTracer, emitLlmSelftestTrace, normalizeTraces; scopes @autter/runtime-node; dependent files @opentelemetry/api, @opentelemetry/exporter-metrics-otlp-http, @opentelemetry/exporter-trace-otlp-http, @opentelemetry/instrumentation-http, @opentelemetry/resources, @opentelemetry/sdk-metrics, @opentelemetry/sdk-node, @opentelemetry/sdk-trace-base.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Functions/symbols:
AutterServerOptions,AutterSeverity,LlmUsage,initAutterServer,autterLlmTracer,emitLlmSelftestTrace,normalizeTraces - Dependent files:
@opentelemetry/api,@opentelemetry/exporter-metrics-otlp-http,@opentelemetry/exporter-trace-otlp-http,@opentelemetry/instrumentation-http,@opentelemetry/resources,@opentelemetry/sdk-metrics,@opentelemetry/sdk-node,@opentelemetry/sdk-trace-base - Scopes:
@autter/runtime-node
🛠 AI fix prompt (copy & paste into your coding agent)
In `packages/runtime-node/src/server.ts`, update `withSampledFlag` to store `span.spanContext` in a local variable before constructing the sampled context, then reuse that variable for both the spread and `traceFlags` calculation. Preserve the existing sampled flag and `autter.tail_retained` behavior. Blast radius — if this hygiene issue is left in it makes the downstream usage that depends on this file harder to change safely: functions `AutterServerOptions`, `AutterSeverity`, `LlmUsage`, `initAutterServer`, `autterLlmTracer`, `emitLlmSelftestTrace`, `normalizeTraces`; scopes `@autter/runtime-node`; dependent files `@opentelemetry/api`, `@opentelemetry/exporter-metrics-otlp-http`, `@opentelemetry/exporter-trace-otlp-http`, `@opentelemetry/instrumentation-http`, `@opentelemetry/resources`, `@opentelemetry/sdk-metrics`, `@opentelemetry/sdk-node`, `@opentelemetry/sdk-trace-base`.
Flagged by Autter security & observability checks.
| // The local root ended: the request is over, and an error inside it | ||
| // would have surfaced by now. Drop a healthy trace's buffer; keep | ||
| // retained entries so late stragglers still export (sweep cleans up). | ||
| if (span.parentSpanId === undefined && !entry.retained) { |
There was a problem hiding this comment.
🟠 [ai] Late child errors cannot rescue an unsampled trace after its root ends — Risk: 70/100
ErrorTraceRetentionProcessor drops an unsampled trace's buffered spans immediately when its local root ends healthy. If an asynchronous child subsequently ends with an error, entryFor() creates a new retention entry and only that child is exported; the root and previously completed sibling spans have already been discarded. Retain the trace buffer until the configured TTL or otherwise account for late children before dropping it.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Functions/symbols:
AutterServerOptions,AutterSeverity,LlmUsage,initAutterServer,autterLlmTracer,emitLlmSelftestTrace,normalizeTraces - Dependent files:
@opentelemetry/api,@opentelemetry/exporter-metrics-otlp-http,@opentelemetry/exporter-trace-otlp-http,@opentelemetry/instrumentation-http,@opentelemetry/resources,@opentelemetry/sdk-metrics,@opentelemetry/sdk-node,@opentelemetry/sdk-trace-base - Scopes:
@autter/runtime-node
🛠 AI fix prompt (copy & paste into your coding agent)
Do not discard a healthy trace's buffered spans solely when the root span ends. Keep the entry through a bounded grace period or until all known spans have ended, and ensure a late child error can still flush the previously buffered root and sibling spans without allowing the retention buffer to grow unbounded. Blast radius — if this defect reaches production it can fail the downstream usage that depends on this file: functions `AutterServerOptions`, `AutterSeverity`, `LlmUsage`, `initAutterServer`, `autterLlmTracer`, `emitLlmSelftestTrace`, `normalizeTraces`; scopes `@autter/runtime-node`; dependent files `@opentelemetry/api`, `@opentelemetry/exporter-metrics-otlp-http`, `@opentelemetry/exporter-trace-otlp-http`, `@opentelemetry/instrumentation-http`, `@opentelemetry/resources`, `@opentelemetry/sdk-metrics`, `@opentelemetry/sdk-node`, `@opentelemetry/sdk-trace-base`.
Flagged by Autter security & observability checks.
🚦 Pre-merge checks ·
|
| Check | Status | Explanation |
|---|---|---|
| Batch size limit not detected | 1 potential issue(s) detected (max risk 58/100): packages/runtime-node/src/server.ts:275. | |
| Missing linked tracker issue | 2 potential issue(s) detected (max risk 55/100): packages/runtime-node/src/server.ts:7, packages/runtime-node/src/server.ts:77. | |
| Missing CODEOWNERS reviewer approval | 1 potential issue(s) detected (max risk 70/100): packages/runtime-node/src/server.ts:7. | |
| Source changes without matching tests | 3 potential issue(s) detected (max risk 75/100): packages/runtime-node/src/server.ts:7, packages/runtime-node/src/server.ts:77, packages/otlp-ingester/src/normalize-otlp.ts:333. | |
| Generic placeholder identifier in production logic | 1 potential issue(s) detected (max risk 45/100): packages/runtime-node/src/server.ts:283. | |
| Unhandled edge case (null / empty / zero / boundary) | 1 potential issue(s) detected (max risk 65/100): packages/runtime-node/src/server.ts:334. | |
| Data integrity risk | 1 finding(s) on changed lines. | |
| Simplifiable code | 1 finding(s) on changed lines. | |
| Code duplication / DRY violation | 1 finding(s) on changed lines. |
✅ Passed checks (160)
| Check | Status | Explanation |
|---|---|---|
| Too many files changed | ✅ Passed | Changed 8 file(s), within the limit of 50. |
| Too many lines changed | ✅ Passed | Changed 360 line(s), within the limit of 1000. |
| Too many unrelated chapters | ✅ Passed | 4 chapter(s) detected, within the limit of 6. |
| Generated files hiding real changes | ✅ Passed | Generated-file volume (0 lines) does not obscure the 360 hand-written line(s). |
| Missing PR context | ✅ Passed | PR context looks sufficient. |
| Mixed concerns (refactor + behavior change) | ✅ Passed | The PR contains behavior changes plus Docker and documentation fixes, but no apparent refactor-only changes. |
| Migration + app logic + UI combined in one PR | ✅ Passed | No database migrations or user-interface changes are present. |
| Sensitive data in logs | ✅ Passed | No sensitive data in logs issues detected. |
| Log injection | ✅ Passed | No log injection issues detected. |
| Missing audit logging | ✅ Passed | No missing audit logging issues detected. |
| Removed observability | ✅ Passed | No removed observability issues detected. |
| Silent exception swallowing | ✅ Passed | No silent exception swallowing issues detected. |
| Unhandled promise rejection | ✅ Passed | No unhandled promise rejection issues detected. |
| Circuit breaker not detected | ✅ Passed | No circuit breaker not detected issues detected. |
| Stack trace leakage | ✅ Passed | No stack trace leakage issues detected. |
| Multi-write without detected transaction | ✅ Passed | No multi-write without detected transaction issues detected. |
| Possible TOCTOU in critical path | ✅ Passed | No possible toctou in critical path issues detected. |
| Idempotency key not detected | ✅ Passed | No idempotency key not detected issues detected. |
| Possible non-atomic read-modify-write | ✅ Passed | No possible non-atomic read-modify-write issues detected. |
| Optimistic locking not detected | ✅ Passed | No optimistic locking not detected issues detected. |
| Rate limiting not detected | ✅ Passed | No rate limiting not detected issues detected. |
| Rate limiting removed | ✅ Passed | No rate limiting removed issues detected. |
| Pagination not detected | ✅ Passed | No pagination not detected issues detected. |
| Publicly exposed storage | ✅ Passed | No publicly exposed storage issues detected. |
| Over-permissive IAM policy | ✅ Passed | No over-permissive iam policy issues detected. |
| Security group open to the internet | ✅ Passed | No security group open to the internet issues detected. |
| Unencrypted storage at rest | ✅ Passed | No unencrypted storage at rest issues detected. |
| Infrastructure missing access logging | ✅ Passed | No infrastructure missing access logging issues detected. |
| Hardcoded secret in IaC | ✅ Passed | No hardcoded secret in iac issues detected. |
| Infrastructure misconfiguration | ✅ Passed | No infrastructure misconfiguration issues detected. |
| Deprecated Kubernetes API version | ✅ Passed | No deprecated kubernetes api version issues detected. |
| Compound IaC attack chain | ✅ Passed | No compound iac attack chain issues detected. |
| Prompt injection risk | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| LLM output used in a dangerous sink | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Sensitive data in prompt or system-prompt leakage | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Over-privileged LLM tool / excessive agency | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Missing validation on an LLM-driven decision | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Unbounded LLM usage (denial-of-wallet) | ✅ Passed | No LLM/AI-integration code touched by this diff. |
| Table exposed without row-level security | ✅ Passed | No row-level-security-related code touched by this diff. |
| Over-broad row-level security policy | ✅ Passed | No row-level-security-related code touched by this diff. |
| Code path that bypasses row-level security | ✅ Passed | No row-level-security-related code touched by this diff. |
| Privileged database credential reachable from the client | ✅ Passed | No row-level-security-related code touched by this diff. |
| Privileged query without row-level scoping | ✅ Passed | No row-level-security-related code touched by this diff. |
| Template-default gradient styling | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Interchangeable AI marketing copy | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Placeholder content shipped to users | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Emoji standing in for an icon system | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Call-to-action that goes nowhere | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Templated page composition | ✅ Passed | No added frontend pages or design-slop markers in this diff. |
| Merge-blocking marker left in the change | ✅ Passed | No pending-work markers added by this diff. |
| Known-defect marker shipped in code | ✅ Passed | No pending-work markers added by this diff. |
| Untracked TODO without an issue reference | ✅ Passed | No pending-work markers added by this diff. |
| Test disabled or left pending | ✅ Passed | No pending-work markers added by this diff. |
| PII in logs | ✅ Passed | No pii in logs issues detected. |
| PII or internals leaked in error response | ✅ Passed | No pii or internals leaked in error response issues detected. |
| PII stored without application-level encryption | ✅ Passed | No pii stored without application-level encryption issues detected. |
| User data stored without retention controls | ✅ Passed | No user data stored without retention controls issues detected. |
| PII sent to external / cross-border destination | ✅ Passed | No pii sent to external / cross-border destination issues detected. |
| Lockfile resolution / integrity tampered | ✅ Passed | No lockfile resolution / integrity tampered issues detected. |
| Dependency runs install-time lifecycle script | ✅ Passed | No dependency runs install-time lifecycle script issues detected. |
| Possible dependency-confusion attack | ✅ Passed | No possible dependency-confusion attack issues detected. |
| Lockfile resolves a dependency the manifest does not declare | ✅ Passed | No lockfile resolves a dependency the manifest does not declare issues detected. |
| Checked-in build artefact modified without source change | ✅ Passed | No checked-in build artefact modified without source change issues detected. |
| Dockerfile build-step is insecure | ✅ Passed | No dockerfile build-step is insecure issues detected. |
| External artefact pulled in without integrity pinning | ✅ Passed | No external artefact pulled in without integrity pinning issues detected. |
| Changed export, importer not updated | ✅ Passed | No changed export with an un-updated importer detected. |
| Missing security-team review on sensitive path | ✅ Passed | No missing security-team review on sensitive path issues detected. |
| Migration missing rollback / down step | ✅ Passed | No migration missing rollback / down step issues detected. |
| Frontend importing database client directly | ✅ Passed | No frontend importing database client directly issues detected. |
| Route handler bypassing service layer | ✅ Passed | No route handler bypassing service layer issues detected. |
| Backend service importing UI module | ✅ Passed | No backend service importing ui module issues detected. |
| Cross-context internals import | ✅ Passed | No cross-context internals import issues detected. |
| Workspace package rule violation | ✅ Passed | No workspace package rule violation issues detected. |
| Inconsistent logging pattern | ✅ Passed | No inconsistent logging pattern issues detected. |
| Inconsistent error handling | ✅ Passed | No inconsistent error handling issues detected. |
| Endpoint missing input validation | ✅ Passed | No endpoint missing input validation issues detected. |
| Multi-write without transaction wrapper | ✅ Passed | No multi-write without transaction wrapper issues detected. |
| New feature shipped without feature flag | ✅ Passed | No new feature shipped without feature flag issues detected. |
| Module placed in the wrong workspace package | ✅ Passed | No module placed in the wrong workspace package issues detected. |
| Direct env-var access bypasses config module | ✅ Passed | No direct env-var access bypasses config module issues detected. |
| Hallucinated import (package not installed) | ✅ Passed | No hallucinated import (package not installed) issues detected. |
| Nonexistent package (not found in registry) | ✅ Passed | No nonexistent package (not found in registry) issues detected. |
| Call to function that does not exist | ✅ Passed | No call to function that does not exist issues detected. |
| Repetitive boilerplate (duplicated block) | ✅ Passed | No repetitive boilerplate (duplicated block) issues detected. |
| Overbroad try/catch swallowing all exceptions | ✅ Passed | No overbroad try/catch swallowing all exceptions issues detected. |
| TODO / FIXME on critical path | ✅ Passed | No todo / fixme on critical path issues detected. |
| Comment contradicts or fabricates code behaviour | ✅ Passed | No comment contradicts or fabricates code behaviour issues detected. |
| Abstraction defined but never used | ✅ Passed | No abstraction defined but never used issues detected. |
| Code style differs from rest of codebase | ✅ Passed | No code style differs from rest of codebase issues detected. |
| Established pattern ignored | ✅ Passed | No established pattern ignored issues detected. |
| Doc-copy code with insecure defaults | ✅ Passed | No doc-copy code with insecure defaults issues detected. |
| Dead code (defined but never referenced) | ✅ Passed | No dead code (defined but never referenced) issues detected. |
| Deprecated API call | ✅ Passed | No deprecated api call issues detected. |
| API pattern from wrong library version | ✅ Passed | No api pattern from wrong library version issues detected. |
| API endpoint removed | ✅ Passed | No api endpoint removed issues detected. |
| HTTP method changed (GET ↔ POST etc.) | ✅ Passed | No http method changed (get ↔ post etc.) issues detected. |
| New required field added to request | ✅ Passed | No new required field added to request issues detected. |
| Field removed from response schema | ✅ Passed | No field removed from response schema issues detected. |
| Response field type changed | ✅ Passed | No response field type changed issues detected. |
| HTTP status code changed | ✅ Passed | No http status code changed issues detected. |
| Auth requirement added / removed / changed | ✅ Passed | No auth requirement added / removed / changed issues detected. |
| Error response shape changed | ✅ Passed | No error response shape changed issues detected. |
| Pagination behaviour changed | ✅ Passed | No pagination behaviour changed issues detected. |
| Outbound webhook payload schema changed | ✅ Passed | No outbound webhook payload schema changed issues detected. |
| GraphQL field removed without deprecation | ✅ Passed | No graphql field removed without deprecation issues detected. |
| GraphQL enum value removed | ✅ Passed | No graphql enum value removed issues detected. |
| SQL injection | ✅ Passed | No sql injection issues detected. |
| Cross-site scripting (XSS) | ✅ Passed | No cross-site scripting (xss) issues detected. |
| Path traversal | ✅ Passed | No path traversal issues detected. |
| Command injection | ✅ Passed | No command injection issues detected. |
| Insecure deserialization | ✅ Passed | No insecure deserialization issues detected. |
| Weak cryptography | ✅ Passed | No weak cryptography issues detected. |
| Hardcoded secret | ✅ Passed | No hardcoded secret issues detected. |
| Insecure randomness for security material | ✅ Passed | No insecure randomness for security material issues detected. |
| Unsafe file upload | ✅ Passed | No unsafe file upload issues detected. |
| Missing input validation | ✅ Passed | No missing input validation issues detected. |
| Unsafe CORS configuration | ✅ Passed | No unsafe cors configuration issues detected. |
| Unsafe / open redirect | ✅ Passed | No unsafe / open redirect issues detected. |
| Missing CSRF protection | ✅ Passed | No missing csrf protection issues detected. |
| Unsafe cookie / session settings | ✅ Passed | No unsafe cookie / session settings issues detected. |
| Sensitive data exposure | ✅ Passed | No sensitive data exposure issues detected. |
| API key in source | ✅ Passed | No api key in source detected. |
| Access token in source | ✅ Passed | No access token in source detected. |
| Private key in source | ✅ Passed | No private key in source detected. |
| Database connection URL with embedded credentials | ✅ Passed | No database connection url with embedded credentials detected. |
| Cloud credential in source | ✅ Passed | No cloud credential in source detected. |
| Webhook signing secret in source | ✅ Passed | No webhook signing secret in source detected. |
| OAuth client secret in source | ✅ Passed | No oauth client secret in source detected. |
| JWT signing secret in source | ✅ Passed | No jwt signing secret in source detected. |
| Hardcoded password | ✅ Passed | No hardcoded password detected. |
| Auth middleware removed from route | ✅ Passed | No auth middleware removed from route issues detected. |
| Route protection changed (protected → public) | ✅ Passed | No route protection changed (protected → public) issues detected. |
| Permission / RBAC check removed | ✅ Passed | No permission / rbac check removed issues detected. |
| Required role weakened | ✅ Passed | No required role weakened issues detected. |
| Admin-only route exposed to lower privilege | ✅ Passed | No admin-only route exposed to lower privilege issues detected. |
| Token validation skipped in middleware chain | ✅ Passed | No token validation skipped in middleware chain issues detected. |
| JWT verification weakened or changed | ✅ Passed | No jwt verification weakened or changed issues detected. |
| Session expiration / TTL changed | ✅ Passed | No session expiration / ttl changed issues detected. |
| Password reset flow changed | ✅ Passed | No password reset flow changed issues detected. |
| OAuth callback / redirect handling changed | ✅ Passed | No oauth callback / redirect handling changed issues detected. |
| Webhook endpoint missing signature verification | ✅ Passed | No webhook endpoint missing signature verification issues detected. |
| Public route touches private/PII data | ✅ Passed | No public route touches private/pii data issues detected. |
| Frontend performance issue | ✅ Passed | No additional explanation was reported. |
| Frontend security issue | ✅ Passed | No additional explanation was reported. |
| Frontend correctness issue | ✅ Passed | No additional explanation was reported. |
| Accessibility issue | ✅ Passed | No additional explanation was reported. |
| Frontend maintainability issue | ✅ Passed | No additional explanation was reported. |
| Code correctness issue | ✅ Passed | No additional explanation was reported. |
| Runtime error risk | ✅ Passed | No additional explanation was reported. |
| Resource leak risk | ✅ Passed | No additional explanation was reported. |
| Maintainability issue | ✅ Passed | No additional explanation was reported. |
| Co-change coupling | ✅ Passed | No additional explanation was reported. |
| Redundant alias / duplicate import | ✅ Passed | No additional explanation was reported. |
| Redundant type construct | ✅ Passed | No additional explanation was reported. |
| Unnecessary type assertion | ✅ Passed | No additional explanation was reported. |
| Module smell | ✅ Passed | No additional explanation was reported. |
| Excessive complexity | ✅ Passed | No additional explanation was reported. |
| Dead export (no callers) | ✅ Passed | No additional explanation was reported. |
| Complexity Guard | ✅ Passed | No additional explanation was reported. |
| Bundle Size Monitor | ✅ Passed | No additional explanation was reported. |
This comment is updated automatically whenever Autter reviews a new PR revision.
🧭 PR hygiene & process suggestionsAutter has 4 suggestion(s) about the shape of this PR (size, scope, reviewability). These are process guidance — not code defects — so they are consolidated here instead of posted as inline comments on individual files. 🟠 Source changes without matching tests — Risk: 75/100This source file was changed but no sibling test file is added or modified anywhere in the PR. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: functions 🛠 AI fix prompt (copy & paste into your coding agent)🟠 Source changes without matching tests — Risk: 75/100The new RecordUnsampledSampler and ErrorTraceRetentionProcessor alter initAutterServer, captureException, captureMessage, and exported AutterServerOptions behavior, but no sibling test file is added or modified. Regressions could stop unsampled spans from being rescued, export incomplete traces, or change sampling and error-capture behavior for all Node SDK users. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: functions 🛠 AI fix prompt (copy & paste into your coding agent)🟠 Source changes without matching tests — Risk: 65/100The normalizeTraces server-span rollup condition now excludes spans marked 🛠 AI fix prompt (copy & paste into your coding agent)🟠 Missing linked tracker issue — Risk: 50/100This PR's title and body do not reference any tracker issue (GitHub 🛠 AI fix prompt (copy & paste into your coding agent)Flagged by Autter PR-hygiene checks.
|
| retainActiveTrace(): void { | ||
| const active = trace.getActiveSpan()?.spanContext(); | ||
| // No active trace, or a head-sampled one that exports anyway. | ||
| if (!active || (active.traceFlags & TraceFlags.SAMPLED) !== 0) return; |
There was a problem hiding this comment.
🟠 [ai] Nested always-on spans prevent error retention from promoting the unsampled request trace — Risk: 78/100
The documented tail-retention contract is not preserved when a request contains a nested withProcessSpan or withLlmCall: those helpers are called through server.ts:771-774 and create spans on the separate AlwaysOnSampler provider, so the active span seen by retainActiveTrace() is sampled even when the enclosing HTTP trace was head-unsampled. The guard at this line returns in that case, leaving the request spans buffered but never flushed when captureException or an error-severity captureMessage is called inside the nested helper. The error occurrence is still emitted by the always-on tracer, but the full trace that the new option promises is lost for this common cross-file call chain.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
packages/runtime-node/src/server.ts,packages/runtime-node/README.md
🛠 AI fix prompt (copy & paste into your coding agent)
Make error retention resolve the unsampled parent/request trace rather than rejecting the active always-on child context, for example by preserving the parent trace context when entering always-on helper spans or by walking/identifying the enclosing unsampled trace before applying the sampled guard. Ensure captureException and error-severity captureMessage inside withProcessSpan/withLlmCall promote and flush the enclosing trace.
Flagged by Autter security & observability checks.
| // ships those at ~100% alongside a metrics pipeline that already | ||
| // counts every request, so folding them in would double-count | ||
| // erroring routes. | ||
| if (kind === "server" && attrs.get("autter.tail_retained") !== "true") { |
There was a problem hiding this comment.
🟠 [ai] Tail-retained requests are dropped from fallback usage rollups — Risk: 78/100
This condition excludes every tail-retained server span from metricPoints, but the trace and metric pipelines are independent: /v1/traces calls normalizeTraces and stores its rollups, while /v1/metrics is a separate request that may be absent or fail. Therefore any unsampled request that later errors is exported with autter.tail_retained and contributes no request or error rollup when metrics are not wired, delayed, or unavailable, even though this code is specifically the fallback that is supposed to track usage without metrics. The change fixes double counting only when a matching metric histogram is actually delivered; without proving that, it causes systematic undercounting of erroring requests in a documented supported configuration.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
packages/otlp-ingester/src/normalize-otlp.ts,packages/otlp-ingester/src/server.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Do not suppress the span-derived rollup solely from the tail-retained marker unless the ingester has positively established that the corresponding metric point was received and will be counted. Otherwise retain the fallback rollup, or add an explicit deduplication mechanism keyed by service/environment/release/route/time bucket.
Flagged by Autter security & observability checks.
| if (!active || (active.traceFlags & TraceFlags.SAMPLED) !== 0) return; | ||
| const entry = this.entryFor(active.traceId); | ||
| if (entry.retained) return; | ||
| entry.retained = true; |
There was a problem hiding this comment.
🟠 [ai] Retained-trace markers bypass the global buffer bound — Risk: 61/100
Once an unsampled trace is promoted, retainActiveTrace marks its entry retained and flushes its spans, but leaves the entry in traces; evictIfOverBudget intentionally skips entries with no buffered spans, and the only cleanup is the 30-second sweep. A burst of distinct erroring traces therefore creates one retained map entry per trace without being counted by bufferedSpans or constrained by RETENTION_MAX_BUFFERED_SPANS. Under high error traffic this can retain tens of thousands of trace IDs and entry objects simultaneously, adding avoidable memory pressure on the failure path precisely when the service is degraded.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
packages/runtime-node/src/server.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Bound retained trace metadata separately from buffered spans, or delete retained entries once their root/late-span window is complete; enforce a maximum retained-trace count and evict old entries when it is exceeded.
Flagged by Autter security & observability checks.
|
Autter found 1 issue(s) it could not attach to the current diff (the anchor line is not part of a diff hunk, or the PR advanced during the review): 🔴 [ai] Uncaught-process flush does not flush rescued traces (risk 82/100)
When an uncaught exception terminates the process,
|
| | Handled errors | `captureException(err)` | `captureException(err)` | | ||
| | Usage | session pings + `trackEvent()` | request counts/durations per route (automatic) | | ||
| | Traces | — (by design; no OTel in the browser) | ~1% sampled (configurable) | | ||
| | Traces | — (by design; no OTel in the browser) | ~1% sampled, plus **every erroring trace kept in full** | |
There was a problem hiding this comment.
🟡 [deterministic] markdownlint: MD013 — Risk: 30/100
Line length: Expected: 80; Actual: 108
🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at docs/GETTING-STARTED.md:44: Line length: Expected: 80; Actual: 108
Flagged by Autter security & observability checks.
|
Autter's deep review traced 1 finding(s) to file(s) this PR does not change — they can't be shown as inline comments, but the change still affects them: 🔴 [deterministic] Build failed: example-express-app (risk 80/100)
What happened: The How to fix: Add a Build output |
🧪 Autter test runAutter executed the automated checks against
Declared tests: 4 test file(s) found — 0 ran, 0 not observed in suite output, 4 did not run.
|
| Changed file | Related test | Result |
|---|---|---|
packages/runtime-node/src/server.ts |
packages/otlp-ingester/src/normalize.test.ts |
✅ no declared test — temporary test passed |
packages/otlp-ingester/src/normalize-otlp.ts |
— | ✅ no declared test — temporary test passed |
🤖 Coverage-check evidence
packages/runtime-node/src/server.ts
Ran: npx tsx --test src/normalize.test.ts (from packages/otlp-ingester); npx tsx --test .autter/scratch/normalize-tail-retained.test.ts (from repository root)
Declared test: 4 passed, 0 failed, but its server-span cases do not set autter.tail_retained and do not exercise the changed branch. Temporary test: 1 passed, 0 failed; tail-retained server span produced 1 normalized span and 0 metric rollups.
packages/otlp-ingester/src/normalize-otlp.ts
Ran: npm run build -w @autter/runtime-node; npx tsx --test .autter/scratch/runtime-retention.test.ts (from repository root)
Build succeeded (ESM, CJS, and DTS). Temporary behavioral test: 1 passed, 0 failed; with traceSampleRate 0, an unsampled root plus errored child produced 2 exported spans, both carrying autter.tail_retained=true.
Temporary tests are written under .autter/scratch/ for verification only — they are never committed to the repository.
Test plan (from the PR description)
- ❌ Run the repository's formatting, type-checking, build, and CI validation commands. — agent execution observed the wrong behavior
- ⬜ Start the root Docker Compose stack with
docker compose upand verify ClickHouse becomes healthy and the ingester listens on port 4318. — Docker Compose stack and service health were not tested. - ❌ Configure
traceSampleRate: 0withretainTracesOnError: true, generate a request that returns a 5xx or records an exception, and verify the complete trace is received by the ingester. — agent execution observed the wrong behavior - ✅ Generate a healthy request with the same sampling configuration and verify it is not exported. — verified by agent execution
- ✅ Set
retainTracesOnError: false, repeat the erroring request, and verify it follows head-sampling behavior. — verified by agent execution - ✅ Send retained traces through the ingester and verify their spans are excluded from span-fed request usage rollups. — verified by agent execution
- ⬜ Exercise the buffer overflow and expiry paths to confirm telemetry continues without blocking or unbounded memory growth. — Buffer overflow and expiry paths were not tested.
🤖 Agent-executed checks
❌ Run the repository's formatting, type-checking, build, and CI validation commands.
Ran: npm install --include=dev --ignore-scripts; npm run build; npm run size -w @autter/runtime-browser; npm run format --if-present; npm run typecheck --if-present; npm test -w @autter/otlp-ingester
Build completed for browser, node, ingester, and next; ingester tests passed 18/18. Browser size failed: "Size Limit can’t find files at dist/index.js". No root format/typecheck scripts were defined, so those commands produced no output.
❌ Configure traceSampleRate: 0 with retainTracesOnError: true, generate a request that returns a 5xx or records an exception, and verify the complete trace is received by the ingester.
Ran: npx tsx .autter/scratch/retention-check.ts with traceSampleRate: 0 and retainTracesOnError: true, local HTTP OTLP capture, and an error-status request span
Healthy trace exported 0 spans, but error case exported 0 spans; expected a complete retained trace. Assertion failed: retained.length >= 1.
✅ Generate a healthy request with the same sampling configuration and verify it is not exported.
Ran: npx tsx .autter/scratch/retention-check.ts with traceSampleRate: 0 and retainTracesOnError: true, local HTTP OTLP capture, healthy request span
Observed healthy: { count: 0, names: [] }.
✅ Set retainTracesOnError: false, repeat the erroring request, and verify it follows head-sampling behavior.
Ran: npx tsx .autter/scratch/retention-check.ts with traceSampleRate: 0 and retainTracesOnError: false, local HTTP OTLP capture, error-status request span
Observed noRetention: { count: 0, names: [] }, matching head-sampling at rate 0.
✅ Send retained traces through the ingester and verify their spans are excluded from span-fed request usage rollups.
Ran: npx tsx .autter/scratch/rollup-check.ts; normalizeTraces() with server span carrying autter.tail_retained=true and a comparison span without it
Observed retainedMetricPoints: [] and normalMetricPoints with requestCount 1/errorCount 1. Tail-retained server span was excluded from span-fed rollups.
⬜ items could not be verified automatically and still need a manual check.
There was a problem hiding this comment.
🔴 Autter review in progress — running security, correctness & dependency checks on this PR. Follow live step-by-step progress on the autter/review-gate check in the merge box. Merge is blocked until the gate completes; Autter approves automatically when the review comes back clean, and releases this hold with a neutral review when it finds non-blocking issues.
| sampler, | ||
| spanProcessors: [ | ||
| new BatchSpanProcessor( | ||
| new OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers }), |
There was a problem hiding this comment.
🟡 [ai] Code duplication / DRY violation — Risk: 20/100
initAutterServer duplicates OTLPTraceExporter construction and its endpoint/header configuration for the two batch processors, making future exporter changes easy to miss and affecting both regular and rescued trace export paths. Blast radius — if this hygiene issue is left in it makes the downstream usage that depends on this file harder to change safely: functions AutterServerOptions, AutterSeverity, LlmUsage, initAutterServer, autterLlmTracer, emitLlmSelftestTrace, normalizeTraces; scopes @autter/runtime-node; dependent files @opentelemetry/api, @opentelemetry/core, @opentelemetry/exporter-metrics-otlp-http, @opentelemetry/exporter-trace-otlp-http, @opentelemetry/instrumentation-http, @opentelemetry/resources, @opentelemetry/sdk-metrics, @opentelemetry/sdk-node.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Functions/symbols:
AutterServerOptions,AutterSeverity,LlmUsage,initAutterServer,autterLlmTracer,emitLlmSelftestTrace,normalizeTraces - Dependent files:
@opentelemetry/api,@opentelemetry/core,@opentelemetry/exporter-metrics-otlp-http,@opentelemetry/exporter-trace-otlp-http,@opentelemetry/instrumentation-http,@opentelemetry/resources,@opentelemetry/sdk-metrics,@opentelemetry/sdk-node - Scopes:
@autter/runtime-node
🛠 AI fix prompt (copy & paste into your coding agent)
Extract the shared OTLPTraceExporter construction or configuration into a small factory/helper, then use it for both BatchSpanProcessor instances while preserving the distinct processor settings and flush cadence. Blast radius — if this hygiene issue is left in it makes the downstream usage that depends on this file harder to change safely: functions `AutterServerOptions`, `AutterSeverity`, `LlmUsage`, `initAutterServer`, `autterLlmTracer`, `emitLlmSelftestTrace`, `normalizeTraces`; scopes `@autter/runtime-node`; dependent files `@opentelemetry/api`, `@opentelemetry/core`, `@opentelemetry/exporter-metrics-otlp-http`, `@opentelemetry/exporter-trace-otlp-http`, `@opentelemetry/instrumentation-http`, `@opentelemetry/resources`, `@opentelemetry/sdk-metrics`, `@opentelemetry/sdk-node`.
Flagged by Autter security & observability checks.
| function withSampledFlag(span: ReadableSpan): ReadableSpan { | ||
| const spanContext = { | ||
| ...span.spanContext(), | ||
| traceFlags: span.spanContext().traceFlags | TraceFlags.SAMPLED, |
There was a problem hiding this comment.
🟡 [ai] Simplifiable code — Risk: 10/100
withSampledFlag calls span.spanContext twice while constructing the same context, creating needless repeated work in the trace-retention export path. Blast radius — if this hygiene issue is left in it makes the downstream usage that depends on this file harder to change safely: functions AutterServerOptions, AutterSeverity, LlmUsage, initAutterServer, autterLlmTracer, emitLlmSelftestTrace, normalizeTraces; scopes @autter/runtime-node; dependent files @opentelemetry/api, @opentelemetry/core, @opentelemetry/exporter-metrics-otlp-http, @opentelemetry/exporter-trace-otlp-http, @opentelemetry/instrumentation-http, @opentelemetry/resources, @opentelemetry/sdk-metrics, @opentelemetry/sdk-node.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Functions/symbols:
AutterServerOptions,AutterSeverity,LlmUsage,initAutterServer,autterLlmTracer,emitLlmSelftestTrace,normalizeTraces - Dependent files:
@opentelemetry/api,@opentelemetry/core,@opentelemetry/exporter-metrics-otlp-http,@opentelemetry/exporter-trace-otlp-http,@opentelemetry/instrumentation-http,@opentelemetry/resources,@opentelemetry/sdk-metrics,@opentelemetry/sdk-node - Scopes:
@autter/runtime-node
🛠 AI fix prompt (copy & paste into your coding agent)
In withSampledFlag, store span.spanContext in a local variable and spread that variable while deriving traceFlags, so the span context is read only once. Blast radius — if this hygiene issue is left in it makes the downstream usage that depends on this file harder to change safely: functions `AutterServerOptions`, `AutterSeverity`, `LlmUsage`, `initAutterServer`, `autterLlmTracer`, `emitLlmSelftestTrace`, `normalizeTraces`; scopes `@autter/runtime-node`; dependent files `@opentelemetry/api`, `@opentelemetry/core`, `@opentelemetry/exporter-metrics-otlp-http`, `@opentelemetry/exporter-trace-otlp-http`, `@opentelemetry/instrumentation-http`, `@opentelemetry/resources`, `@opentelemetry/sdk-metrics`, `@opentelemetry/sdk-node`.
Flagged by Autter security & observability checks.
| // ships those at ~100% alongside a metrics pipeline that already | ||
| // counts every request, so folding them in would double-count | ||
| // erroring routes. | ||
| if (kind === "server" && attrs.get("autter.tail_retained") !== "true") { |
There was a problem hiding this comment.
🔴 [ai] Wired server spans are double-counted in usage rollups — Risk: 80/100
The rollup condition no longer checks resource.metricsWired, so non-tail-retained server spans from resources that also export request metrics are folded into span-fed rollups and counted again by the metric pipeline. Restore the metrics-wired exclusion while retaining the tail-retention check.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Functions/symbols:
normalizeTraces,addToRollup,routeOf,spanDurationMs,statusCodeOf,severityOf,AutterServerOptions,AutterSeverity - Dependent files:
./fingerprint.js,./llm.js,./types.js - Scopes:
@autter/otlp-ingester
🛠 AI fix prompt (copy & paste into your coding agent)
Keep the `!resource.metricsWired` exclusion for metric-wired resources, and treat the tail-retention marker according to its decoded OTLP type, accepting boolean true (and optionally the string "true" for compatibility). Add tests covering metric-wired regular spans and boolean `autter.tail_retained` spans in `normalizeTraces`. Blast radius — if this defect reaches production it can fail the downstream usage that depends on this file: functions `normalizeTraces`, `addToRollup`, `routeOf`, `spanDurationMs`, `statusCodeOf`, `severityOf`, `AutterServerOptions`, `AutterSeverity`; scopes `@autter/otlp-ingester`; dependent files `./fingerprint.js`, `./llm.js`, `./types.js`.
Flagged by Autter security & observability checks.
🧭 PR hygiene & process suggestionsAutter has 1 suggestion(s) about the shape of this PR (size, scope, reviewability). These are process guidance — not code defects — so they are consolidated here instead of posted as inline comments on individual files. 🟠 Missing linked tracker issue — Risk: 55/100The PR description does not reference a tracker issue using an accepted issue key or closing keyword. The change affects the exported AutterServerOptions and initAutterServer behavior, so its error-retention and sampling changes lack traceable planning context. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: functions 🛠 AI fix prompt (copy & paste into your coding agent)Flagged by Autter PR-hygiene checks.
|
| // ships those at ~100% alongside a metrics pipeline that already | ||
| // counts every request, so folding them in would double-count | ||
| // erroring routes. | ||
| if (kind === "server" && attrs.get("autter.tail_retained") !== "true") { |
There was a problem hiding this comment.
🔴 [ai] Runtime-node requests are double-counted after the metrics-wired guard is removed — Risk: 86/100
This is not safe to ship because the changed server-span branch now adds a span-derived request rollup for every ordinary server span unless it has autter.tail_retained, but the runtime-node caller still marks every resource autter.metrics_wired=true and still exports request histograms. The trace endpoint then persists the new span rollup and the metrics endpoint persists the exact histogram rollup, so each runtime-node request contributes to both runtime_metrics_1m feeds; only tail-retained error spans are excluded, leaving normal sampled requests and non-retained errors duplicated rather than preserving the prior metrics-wired contract.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
packages/runtime-node/src/server.ts,packages/otlp-ingester/src/normalize-otlp.ts,packages/otlp-ingester/src/server.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Restore the `!resource.metricsWired` guard for ordinary server spans, or otherwise ensure runtime-node spans are excluded whenever its request-metrics pipeline is enabled while retaining the tail-retention exclusion.
Flagged by Autter security & observability checks.
| // ships those at ~100% alongside a metrics pipeline that already | ||
| // counts every request, so folding them in would double-count | ||
| // erroring routes. | ||
| if (kind === "server" && attrs.get("autter.tail_retained") !== "true") { |
There was a problem hiding this comment.
🔴 [ai] Runtime server spans are now double-counted against the metrics pipeline — Risk: 86/100
This condition unconditionally creates a request rollup for every ordinary server span and no longer checks the resource's autter.metrics_wired flag. initAutterServer sets that flag to true and configures a periodic OTLP metric reader, so each sampled server span received from the runtime is accompanied by a metrics-pipeline request point. The ingester therefore adds the same request, error, and duration once from metrics and again from the span, inflating traffic and latency totals for the normal runtime-node deployment. The new tail-retained exclusion does not prevent this for healthy or head-sampled requests.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
packages/otlp-ingester/src/normalize-otlp.ts,packages/runtime-node/src/server.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Restore the `!resource.metricsWired` guard for ordinary server-span rollups, or otherwise ensure runtime server spans are not folded when the sender exports request metrics.
Flagged by Autter security & observability checks.
| if (entry.retained) { | ||
| this.forward(span); | ||
| } else if (spanIndicatesError(span)) { | ||
| entry.retained = true; |
There was a problem hiding this comment.
🟠 [ai] Error trace retention has no bound on promoted trace entries — Risk: 78/100
The new default tail-retention path can be driven by an authenticated request that produces an ERROR span (for example, a 5xx response). Each distinct unsampled trace is marked retained and its spans are forwarded, but the documented 5,000-span budget only counts buffered spans; after promotion, the entry remains in the traces map with zero buffered spans and is exempt from eviction. Cleanup is only a 30-second TTL sweep, so a burst of distinct erroring requests can accumulate an unbounded number of retained trace IDs and cause substantial exporter work and memory pressure, while the ingester's per-key request limiter does not cap the number of application requests that can trigger this local amplification. Bound retained entries/exports as well as buffered spans, or apply an explicit per-trace and global error-retention budget with deterministic degradation.
⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:
- Dependent files:
packages/runtime-node/src/server.ts,packages/otlp-ingester/src/server.ts
🛠 AI fix prompt (copy & paste into your coding agent)
Add a hard global cap for retained trace entries and/or retained spans/exports, evict retained entries when the cap is exceeded, and ensure promotion cannot bypass the budget. Preserve the existing TTL cleanup as a secondary safeguard.
Flagged by Autter security & observability checks.
|
Autter found 1 issue(s) it could not attach to the current diff (the anchor line is not part of a diff hunk, or the PR advanced during the review): 🟠 [ai] Tail-retained server errors are counted as an extra event (risk 78/100)
When a tail-retained server span reaches the
|
| | Handled errors | `captureException(err)` | `captureException(err)` | | ||
| | Usage | session pings + `trackEvent()` | request counts/durations per route (automatic) | | ||
| | Traces | — (by design; no OTel in the browser) | ~1% sampled (configurable) | | ||
| | Traces | — (by design; no OTel in the browser) | ~1% sampled, plus **every erroring trace kept in full** | |
There was a problem hiding this comment.
🟡 [deterministic] markdownlint: MD013 — Risk: 30/100
Line length: Expected: 80; Actual: 108
🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at docs/GETTING-STARTED.md:44: Line length: Expected: 80; Actual: 108
Flagged by Autter security & observability checks.
Autter task list
Generated from PR diff, blast radius, and context. Issues found
🛠 Fix optionsCheck one option and Autter will start a fix run for the unresolved issues above.
Checking a box triggers the fix run immediately — Autter comments back with the issues being fixed and the branch created for each. |
Fixes three reported issues: two P2 quickstart breakers and the P2 sampling design gap.
1. Errors kept at 100%, but the trace explaining them was sampled away (~1%)
captureExceptionand crash handling ride an always-on tracer, but the surrounding request trace went throughParentBasedSampler(TraceIdRatioBased(0.01))— so opening a retained error found one lonely error span and no context 99% of the time.Fix: error-linked tail retention in
@autter/runtime-node, default on (retainTracesOnError).RecordUnsampledSamplerupgradesNOT_RECORD→RECORD: head-unsampled traces still materialise in-process, with the W3Ctraceparentunchanged (still unsampled) for downstream services.ErrorTraceRetentionProcessorbuffers finished-but-unsampled spans per trace and exports the whole trace the moment it shows an error: an ERROR-status span (5xx included), anexceptionevent, acaptureException, or an error/fatalcaptureMessageinside it. LLM spans already had this treatment viaLlmAwareSampler; error traces now get the same.autter.tail_retained: true; the ingester now skips those in span-fed usage rollups so erroring routes aren't double-counted (they're already fully counted by thehttp.server.durationmetrics pipeline).runtime_spansunder its existing TTL. For non-Node stacks, INTEGRATIONS.md now recommends an OTel Collectortail_samplingpolicy.2. ClickHouse healthcheck fails on Docker Desktop for Mac
Reproduced live: the container sat
Up (unhealthy)forever, blockingdepends_onand the whole quickstart. Inside the container:wget http://localhost:8123/pingwget http://127.0.0.1:8123/pingOk.wget http://[::1]:8123/pingRoot cause: the image's
<listen_host>::</listen_host>bind fails silently (listen_try 1) on Docker Desktop for Mac, leaving only0.0.0.0listening (netstatshows no tcp6 sockets), while in-containerlocalhostresolves to::1. The healthcheck now pins127.0.0.1— the one listener the image reliably binds — in both the local compose file and the single-server deploy.3. Quickstart didn't say where
instrument.cjsgoesThe guide flowed from
cd autter-runtimestraight intonpm install @autter/runtime-nodeand "createinstrument.cjs", so readers instrumented the cloned ingester repo. Getting-started now states explicitly that the clone only runs the ingester and every instrumentation step happens in the user's own application repository.Created with PostHog Desktop
Summary
Summary generated by Autter.
Adds error-linked trace retention to
@autter/runtime-node, allowing the complete trace for an erroring request to be exported even when healthy traffic is head-sampled. The implementation uses a bounded, expiring in-process span buffer and exposes configuration throughretainTracesOnError. The PR also updates OTLP normalization, documentation, and Docker Compose health checks to improve retained-trace handling and Docker Desktop setup.Changes
packages/runtime-node/src/server.ts:retainTracesOnErroroption, enabled by default, with an opt-out.127.0.0.1in the ClickHouse health check, avoiding Docker Desktop IPv6 resolution issues.Acceptance Criteria
traceSampleRate, and disablingretainTracesOnErrorrestores head-sampling-only behavior.docker compose upreaches a healthy ClickHouse state on Docker Desktop and starts the local ingester successfully.Test Plan
docker compose upand verify ClickHouse becomes healthy and the ingester listens on port 4318.traceSampleRate: 0withretainTracesOnError: true, generate a request that returns a 5xx or records an exception, and verify the complete trace is received by the ingester.retainTracesOnError: false, repeat the erroring request, and verify it follows head-sampling behavior.Rollback Plan
Revert the runtime-node retention changes and the corresponding normalization/docs updates, then rebuild and republish
@autter/runtime-nodeand the ingester image. If deployment rollback is needed before a rebuild, setretainTracesOnError: falsein applications using the new option. Revert the Compose health-check changes only if they cause a deployment-specific compatibility issue.Related Issues
No linked issue was identified.
Written for commit 5475f90. Summary will update on new commits.