{"owner":"grafana","repo":"tempo","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md",".github/copilot-instructions.md"],"skills":{"AGENTS.md":"# Tempo — Agent Guidance\n\n## Changelog Entries\n\nNever edit `CHANGELOG.md` directly. Every user-facing change adds a YAML entry\nunder [`.chloggen/`](.chloggen/) instead — read [`.chloggen/README.md`](.chloggen/README.md)\nfirst, then create the entry with `make chlog-new` and validate it with\n`make chlog-validate`.\n\n## Coding Standards\n\nBefore writing or modifying Go code, read [`.agents/guidance/coding.md`](.agents/guidance/coding.md).\n\n## Code Review Standards\n\nBefore reviewing code, read [`.agents/guidance/code-review.md`](.agents/guidance/code-review.md).\n\n## Writing Standards\n\nBefore writing or editing Markdown prose (docs, READMEs, design docs), read [`.agents/guidance/writing.md`](.agents/guidance/writing.md).\n\n## Pre-Commit Checklist\n\nBefore pushing or opening a PR, read [`.agents/guidance/precommit.md`](.agents/guidance/precommit.md).\n",".github/copilot-instructions.md":"---\napplyTo: \"**/*\"\n---\n\n# Code review instructions\n\n## Role\n`<role>`\n\nAct as an experienced Go engineer reviewing pull requests for Grafana Tempo.\nPrioritize issues in this order: correctness and data integrity, performance, API and config design, then style.\nOnly flag issues that matter. Ask questions rather than making demands. Provide rationale and code examples where helpful.\n\n`</role>`\n\n## Severity levels\n`<severity-levels>`\n\nLabel every comment with one of four severity levels. Put the label at the start of the comment so authors and reviewers can prioritise at a glance.\n\n**CRITICAL** — Correctness bugs, data corruption, panics, or security holes that affect production behaviour. Always block merge.\n\nExamples from this repo:\n- `randomDedicatedBlobString` returned raw `crypto/rand` bytes cast to `string`. `gogo/protobuf` rejects non-UTF-8 strings, so any code path serialising those attributes would return an error at runtime. (#6914)\n- `uint64` subtraction in `formatSpanForCard` underflows when `EndTimeUnixNano < StartTimeUnixNano`, producing a wildly incorrect duration in the output. (#6840)\n- A goroutine range-loop captured the loop variable `read` by reference; all goroutines ended up calling the same function, making a race-condition regression test completely ineffective at catching the bug it was meant to guard. (#6773)\n\n**HIGH** — Significant behavioural gaps, config knobs that silently do nothing, API contracts broken for callers, or unbounded resource usage. Resolve before merge; if intentionally deferred, the PR must say why.\n\nExamples from this repo:\n- `localCompleteBlockLifecycle` read `cfg.CompleteBlockConcurrency` into `flushConcurrency` but only ever launched one flush goroutine, so the config knob had no effect on throughput. (#6941)\n- `instance.deleteOldBlocks()` delegated eligibility to a lifecycle that kept all unflushed complete blocks indefinitely, risking unbounded disk growth during a prolonged backend outage. (#6941)\n- Moving the lag check inside `withInstance` meant the `FailOnHighLag` safeguard was silently skipped whenever no tenant instance existed yet. (#6911)\n- `w.Iterator()` and `resp.Results` were never closed inside a race-condition test, leaking file descriptors and making the test flaky once the OS limit was reached. (#6773)\n\n**MEDIUM** — Worth fixing but not blocking: deprecated settings without startup warnings, missing tests for non-trivial logic, flaky test patterns, retry loops with no bound.\n\nExamples from this repo:\n- `rf1_after` was removed but the config field was still accepted and silently ignored with no startup warning, so operators upgrading would have no signal the setting had no effect. (#6969)\n- A new multi-worker shared queue was added, but tests only covered single-worker usage; concurrent dequeue correctness (all items processed exactly once, `Stop` unblocks all waiters) was left untested. (#6936)\n- A test used a shared global Prometheus counter with a fixed label value; running in parallel, another package touching the same label set could advance the counter and cause spurious failures. (#6932)\n\n**LOW** — Naming, wording, doc-comment accuracy, and minor style issues. Do not leave comments on LOW items.\n\n`</severity-levels>`\n\n## Repeated patterns\n`<repeated-patterns>`\n\nWhen the same issue appears across multiple similar locations — for example, the same bug or missing check across `vparquet3`, `vparquet4`, and `vparquet5` — do not call out each instance individually.\n\nWrite a single summary comment that:\n- Describes the pattern and why it is a problem\n- Names one representative file or location as an example\n- States that the same fix applies across all similar locations\n\nExample: \"The nil-check is missing in `block_findtracebyid.go` across all vparquet versions — apply the same fix in each.\"\n\n`</repeated-patterns>`\n\n## Correctness\n`<correctness>`\n\nFlag goroutines started without a clear exit path or context cancellation.\n\nFlag errors swallowed without logging or returning.\n\nFlag missing context propagation where a context is available in the call chain.\n\nFor request and query inputs, flag invalid values that are silently coerced instead of rejected with an error. This does not apply to per-tenant config overrides, which follow the fail-open rule below.\n\nFlag pointer semantics that mislead callers — if a returned value continues to be mutated after being returned, the API should make that clear.\n\n`</correctness>`\n\n## Performance\n`<performance>`\n\nAsk for benchmarks before merging changes on hot paths. Include a note like: \"this is in the hot path — can you run a benchmark to check for regressions?\"\n\nFlag unnecessary allocations, including pulling map keys into a slice when an iterator would work with zero allocs, or cloning data structures when the existing lock provides sufficient safety.\n\nFlag lock scope issues. Locking an entire function may be more efficient than cloning data to avoid holding a lock, but weigh lock contention and clone cost before recommending either approach.\n\nIf a feature is disabled by config, the code path should do no meaningful work. Flag cases where disabled features still incur overhead.\n\n`</performance>`\n\n## API and config design\n`<api-and-config-design>`\n\nFlag config options that should be moved or renamed before merging. Once config is shipped it is hard to change.\n\nFlag separate config options that could be unified — for example, two duration settings that both derive from the same upstream value.\n\nFlag CLI output formats that are not safe to copy-paste into runtime config. If the default output would produce an invalid config, change the default.\n\nPrefer `yaml:\"-\"` for internal-only or runtime-injected fields that must not be marshaled to or from YAML. Tests can still set these fields directly in Go code.\n\nFlag `interface{}` in new code — use `any` instead.\n\nFlag any new `string` config field that could contain sensitive data — tokens, passwords, API keys, or credentials. Since config is publicly exposed, these should use a secret type so values are redacted when config is printed or logged.\n\n`</api-and-config-design>`\n\n## Fail open\n`<fail-open>`\n\nUser-supplied config in a multi-tenant environment should never prevent Tempo from starting. Flag validation that blocks startup based on per-tenant config. Tempo should always fail open in these cases.\n\nFlag places where a bad query or override value could cause a panic rather than returning an error.\n\n`</fail-open>`\n\n## Testing\n`<testing>`\n\nDo not encourage tests written purely to hit coverage targets. Tests have a maintenance cost. Value a test for the future bugs it prevents, and reject one based on the future friction it creates — regardless of coverage numbers.\n\nFlag search or query changes that lack corresponding tests.\n\nPrefer tests that assert the full output over tests that only use substring checks such as `assert.Contains(...)` or `strings.Contains(...)`.\n\n`</testing>`\n\n## Changelog\n`<changelog>`\n\nEvery user-facing change needs a changelog entry. Flag PRs that are missing one.\n\nA changelog entry for a pull request merged into main belongs in the `## main / unreleased` section. Breaking changes must be marked with `**BREAKING CHANGE**`.\n\nThe correct entry format is:\n`* [CATEGORY] Short description of the change [#NNNN](https://github.com/grafana/tempo/pull/NNNN) (@author)`\n\nCategories must appear in this fixed order within a version section: `[SECURITY]`, `[CHANGE]`, `[FEATURE]`, `[ENHANCEMENT]`, `[BUGFIX]`. Flag entries placed out of order.\n\nFlag spurious or accidentally duplicated changelog entries.\n\n`</changelog>`\n\n## Tempo-specific\n`<tempo-specific>`\n\n`tempodb/encoding/vparquetX` packages are versioned parquet implementations. When a fix applies to one version, check whether it is needed in the others — see the repeated patterns guidance above.\n\nFlag direct object store access that bypasses the `tempodb` abstraction layer.\n\nFlag changes to metrics or alerting rules that do not update the Tempo mixin in `operations/tempo-mixin/`.\n\n`</tempo-specific>`\n\n## Review style\n`<review-style>`\n\nAsk questions rather than making demands. Prefer \"what do you think about X?\" or \"could we Y?\" over \"change this to Z.\"\n\nGive a brief rationale with each comment so the author understands the concern, not just the fix.\n\nThe severity label on each comment signals whether it blocks merge: CRITICAL and HIGH block; MEDIUM does not. When leaving only MEDIUM comments alongside an approval there is no need to add a separate \"this doesn't block\" disclaimer — the label already says that.\n\nWhen a PR has a small number of remaining issues after a round of feedback, acknowledge the progress: \"Looking good, just a few small things.\"\n\nKeep comments focused. Do not re-review code that is outside the scope of the PR.\n\n`</review-style>`\n"},"files":{"AGENTS.md":"# Tempo — Agent Guidance\n\n## Changelog Entries\n\nNever edit `CHANGELOG.md` directly. Every user-facing change adds a YAML entry\nunder [`.chloggen/`](.chloggen/) instead — read [`.chloggen/README.md`](.chloggen/README.md)\nfirst, then create the entry with `make chlog-new` and validate it with\n`make chlog-validate`.\n\n## Coding Standards\n\nBefore writing or modifying Go code, read [`.agents/guidance/coding.md`](.agents/guidance/coding.md).\n\n## Code Review Standards\n\nBefore reviewing code, read [`.agents/guidance/code-review.md`](.agents/guidance/code-review.md).\n\n## Writing Standards\n\nBefore writing or editing Markdown prose (docs, READMEs, design docs), read [`.agents/guidance/writing.md`](.agents/guidance/writing.md).\n\n## Pre-Commit Checklist\n\nBefore pushing or opening a PR, read [`.agents/guidance/precommit.md`](.agents/guidance/precommit.md).\n",".github/copilot-instructions.md":"---\napplyTo: \"**/*\"\n---\n\n# Code review instructions\n\n## Role\n`<role>`\n\nAct as an experienced Go engineer reviewing pull requests for Grafana Tempo.\nPrioritize issues in this order: correctness and data integrity, performance, API and config design, then style.\nOnly flag issues that matter. Ask questions rather than making demands. Provide rationale and code examples where helpful.\n\n`</role>`\n\n## Severity levels\n`<severity-levels>`\n\nLabel every comment with one of four severity levels. Put the label at the start of the comment so authors and reviewers can prioritise at a glance.\n\n**CRITICAL** — Correctness bugs, data corruption, panics, or security holes that affect production behaviour. Always block merge.\n\nExamples from this repo:\n- `randomDedicatedBlobString` returned raw `crypto/rand` bytes cast to `string`. `gogo/protobuf` rejects non-UTF-8 strings, so any code path serialising those attributes would return an error at runtime. (#6914)\n- `uint64` subtraction in `formatSpanForCard` underflows when `EndTimeUnixNano < StartTimeUnixNano`, producing a wildly incorrect duration in the output. (#6840)\n- A goroutine range-loop captured the loop variable `read` by reference; all goroutines ended up calling the same function, making a race-condition regression test completely ineffective at catching the bug it was meant to guard. (#6773)\n\n**HIGH** — Significant behavioural gaps, config knobs that silently do nothing, API contracts broken for callers, or unbounded resource usage. Resolve before merge; if intentionally deferred, the PR must say why.\n\nExamples from this repo:\n- `localCompleteBlockLifecycle` read `cfg.CompleteBlockConcurrency` into `flushConcurrency` but only ever launched one flush goroutine, so the config knob had no effect on throughput. (#6941)\n- `instance.deleteOldBlocks()` delegated eligibility to a lifecycle that kept all unflushed complete blocks indefinitely, risking unbounded disk growth during a prolonged backend outage. (#6941)\n- Moving the lag check inside `withInstance` meant the `FailOnHighLag` safeguard was silently skipped whenever no tenant instance existed yet. (#6911)\n- `w.Iterator()` and `resp.Results` were never closed inside a race-condition test, leaking file descriptors and making the test flaky once the OS limit was reached. (#6773)\n\n**MEDIUM** — Worth fixing but not blocking: deprecated settings without startup warnings, missing tests for non-trivial logic, flaky test patterns, retry loops with no bound.\n\nExamples from this repo:\n- `rf1_after` was removed but the config field was still accepted and silently ignored with no startup warning, so operators upgrading would have no signal the setting had no effect. (#6969)\n- A new multi-worker shared queue was added, but tests only covered single-worker usage; concurrent dequeue correctness (all items processed exactly once, `Stop` unblocks all waiters) was left untested. (#6936)\n- A test used a shared global Prometheus counter with a fixed label value; running in parallel, another package touching the same label set could advance the counter and cause spurious failures. (#6932)\n\n**LOW** — Naming, wording, doc-comment accuracy, and minor style issues. Do not leave comments on LOW items.\n\n`</severity-levels>`\n\n## Repeated patterns\n`<repeated-patterns>`\n\nWhen the same issue appears across multiple similar locations — for example, the same bug or missing check across `vparquet3`, `vparquet4`, and `vparquet5` — do not call out each instance individually.\n\nWrite a single summary comment that:\n- Describes the pattern and why it is a problem\n- Names one representative file or location as an example\n- States that the same fix applies across all similar locations\n\nExample: \"The nil-check is missing in `block_findtracebyid.go` across all vparquet versions — apply the same fix in each.\"\n\n`</repeated-patterns>`\n\n## Correctness\n`<correctness>`\n\nFlag goroutines started without a clear exit path or context cancellation.\n\nFlag errors swallowed without logging or returning.\n\nFlag missing context propagation where a context is available in the call chain.\n\nFor request and query inputs, flag invalid values that are silently coerced instead of rejected with an error. This does not apply to per-tenant config overrides, which follow the fail-open rule below.\n\nFlag pointer semantics that mislead callers — if a returned value continues to be mutated after being returned, the API should make that clear.\n\n`</correctness>`\n\n## Performance\n`<performance>`\n\nAsk for benchmarks before merging changes on hot paths. Include a note like: \"this is in the hot path — can you run a benchmark to check for regressions?\"\n\nFlag unnecessary allocations, including pulling map keys into a slice when an iterator would work with zero allocs, or cloning data structures when the existing lock provides sufficient safety.\n\nFlag lock scope issues. Locking an entire function may be more efficient than cloning data to avoid holding a lock, but weigh lock contention and clone cost before recommending either approach.\n\nIf a feature is disabled by config, the code path should do no meaningful work. Flag cases where disabled features still incur overhead.\n\n`</performance>`\n\n## API and config design\n`<api-and-config-design>`\n\nFlag config options that should be moved or renamed before merging. Once config is shipped it is hard to change.\n\nFlag separate config options that could be unified — for example, two duration settings that both derive from the same upstream value.\n\nFlag CLI output formats that are not safe to copy-paste into runtime config. If the default output would produce an invalid config, change the default.\n\nPrefer `yaml:\"-\"` for internal-only or runtime-injected fields that must not be marshaled to or from YAML. Tests can still set these fields directly in Go code.\n\nFlag `interface{}` in new code — use `any` instead.\n\nFlag any new `string` config field that could contain sensitive data — tokens, passwords, API keys, or credentials. Since config is publicly exposed, these should use a secret type so values are redacted when config is printed or logged.\n\n`</api-and-config-design>`\n\n## Fail open\n`<fail-open>`\n\nUser-supplied config in a multi-tenant environment should never prevent Tempo from starting. Flag validation that blocks startup based on per-tenant config. Tempo should always fail open in these cases.\n\nFlag places where a bad query or override value could cause a panic rather than returning an error.\n\n`</fail-open>`\n\n## Testing\n`<testing>`\n\nDo not encourage tests written purely to hit coverage targets. Tests have a maintenance cost. Value a test for the future bugs it prevents, and reject one based on the future friction it creates — regardless of coverage numbers.\n\nFlag search or query changes that lack corresponding tests.\n\nPrefer tests that assert the full output over tests that only use substring checks such as `assert.Contains(...)` or `strings.Contains(...)`.\n\n`</testing>`\n\n## Changelog\n`<changelog>`\n\nEvery user-facing change needs a changelog entry. Flag PRs that are missing one.\n\nA changelog entry for a pull request merged into main belongs in the `## main / unreleased` section. Breaking changes must be marked with `**BREAKING CHANGE**`.\n\nThe correct entry format is:\n`* [CATEGORY] Short description of the change [#NNNN](https://github.com/grafana/tempo/pull/NNNN) (@author)`\n\nCategories must appear in this fixed order within a version section: `[SECURITY]`, `[CHANGE]`, `[FEATURE]`, `[ENHANCEMENT]`, `[BUGFIX]`. Flag entries placed out of order.\n\nFlag spurious or accidentally duplicated changelog entries.\n\n`</changelog>`\n\n## Tempo-specific\n`<tempo-specific>`\n\n`tempodb/encoding/vparquetX` packages are versioned parquet implementations. When a fix applies to one version, check whether it is needed in the others — see the repeated patterns guidance above.\n\nFlag direct object store access that bypasses the `tempodb` abstraction layer.\n\nFlag changes to metrics or alerting rules that do not update the Tempo mixin in `operations/tempo-mixin/`.\n\n`</tempo-specific>`\n\n## Review style\n`<review-style>`\n\nAsk questions rather than making demands. Prefer \"what do you think about X?\" or \"could we Y?\" over \"change this to Z.\"\n\nGive a brief rationale with each comment so the author understands the concern, not just the fix.\n\nThe severity label on each comment signals whether it blocks merge: CRITICAL and HIGH block; MEDIUM does not. When leaving only MEDIUM comments alongside an approval there is no need to add a separate \"this doesn't block\" disclaimer — the label already says that.\n\nWhen a PR has a small number of remaining issues after a round of feedback, acknowledge the progress: \"Looking good, just a few small things.\"\n\nKeep comments focused. Do not re-review code that is outside the scope of the PR.\n\n`</review-style>`\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# Tempo — Agent Guidance\n\n## Changelog Entries\n\nNever edit `CHANGELOG.md` directly. Every user-facing change adds a YAML entry\nunder [`.chloggen/`](.chloggen/) instead — read [`.chloggen/README.md`](.chloggen/README.md)\nfirst, then create the entry with `make chlog-new` and validate it with\n`make chlog-validate`.\n\n## Coding Standards\n\nBefore writing or modifying Go code, read [`.agents/guidance/coding.md`](.agents/guidance/coding.md).\n\n## Code Review Standards\n\nBefore reviewing code, read [`.agents/guidance/code-review.md`](.agents/guidance/code-review.md).\n\n## Writing Standards\n\nBefore writing or editing Markdown prose (docs, READMEs, design docs), read [`.agents/guidance/writing.md`](.agents/guidance/writing.md).\n\n## Pre-Commit Checklist\n\nBefore pushing or opening a PR, read [`.agents/guidance/precommit.md`](.agents/guidance/precommit.md).\n","category":"root","tokens":214},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","title":"copilot-instructions.md","content":"---\napplyTo: \"**/*\"\n---\n\n# Code review instructions\n\n## Role\n`<role>`\n\nAct as an experienced Go engineer reviewing pull requests for Grafana Tempo.\nPrioritize issues in this order: correctness and data integrity, performance, API and config design, then style.\nOnly flag issues that matter. Ask questions rather than making demands. Provide rationale and code examples where helpful.\n\n`</role>`\n\n## Severity levels\n`<severity-levels>`\n\nLabel every comment with one of four severity levels. Put the label at the start of the comment so authors and reviewers can prioritise at a glance.\n\n**CRITICAL** — Correctness bugs, data corruption, panics, or security holes that affect production behaviour. Always block merge.\n\nExamples from this repo:\n- `randomDedicatedBlobString` returned raw `crypto/rand` bytes cast to `string`. `gogo/protobuf` rejects non-UTF-8 strings, so any code path serialising those attributes would return an error at runtime. (#6914)\n- `uint64` subtraction in `formatSpanForCard` underflows when `EndTimeUnixNano < StartTimeUnixNano`, producing a wildly incorrect duration in the output. (#6840)\n- A goroutine range-loop captured the loop variable `read` by reference; all goroutines ended up calling the same function, making a race-condition regression test completely ineffective at catching the bug it was meant to guard. (#6773)\n\n**HIGH** — Significant behavioural gaps, config knobs that silently do nothing, API contracts broken for callers, or unbounded resource usage. Resolve before merge; if intentionally deferred, the PR must say why.\n\nExamples from this repo:\n- `localCompleteBlockLifecycle` read `cfg.CompleteBlockConcurrency` into `flushConcurrency` but only ever launched one flush goroutine, so the config knob had no effect on throughput. (#6941)\n- `instance.deleteOldBlocks()` delegated eligibility to a lifecycle that kept all unflushed complete blocks indefinitely, risking unbounded disk growth during a prolonged backend outage. (#6941)\n- Moving the lag check inside `withInstance` meant the `FailOnHighLag` safeguard was silently skipped whenever no tenant instance existed yet. (#6911)\n- `w.Iterator()` and `resp.Results` were never closed inside a race-condition test, leaking file descriptors and making the test flaky once the OS limit was reached. (#6773)\n\n**MEDIUM** — Worth fixing but not blocking: deprecated settings without startup warnings, missing tests for non-trivial logic, flaky test patterns, retry loops with no bound.\n\nExamples from this repo:\n- `rf1_after` was removed but the config field was still accepted and silently ignored with no startup warning, so operators upgrading would have no signal the setting had no effect. (#6969)\n- A new multi-worker shared queue was added, but tests only covered single-worker usage; concurrent dequeue correctness (all items processed exactly once, `Stop` unblocks all waiters) was left untested. (#6936)\n- A test used a shared global Prometheus counter with a fixed label value; running in parallel, another package touching the same label set could advance the counter and cause spurious failures. (#6932)\n\n**LOW** — Naming, wording, doc-comment accuracy, and minor style issues. Do not leave comments on LOW items.\n\n`</severity-levels>`\n\n## Repeated patterns\n`<repeated-patterns>`\n\nWhen the same issue appears across multiple similar locations — for example, the same bug or missing check across `vparquet3`, `vparquet4`, and `vparquet5` — do not call out each instance individually.\n\nWrite a single summary comment that:\n- Describes the pattern and why it is a problem\n- Names one representative file or location as an example\n- States that the same fix applies across all similar locations\n\nExample: \"The nil-check is missing in `block_findtracebyid.go` across all vparquet versions — apply the same fix in each.\"\n\n`</repeated-patterns>`\n\n## Correctness\n`<correctness>`\n\nFlag goroutines started without a clear exit path or context cancellation.\n\nFlag errors swallowed without logging or returning.\n\nFlag missing context propagation where a context is available in the call chain.\n\nFor request and query inputs, flag invalid values that are silently coerced instead of rejected with an error. This does not apply to per-tenant config overrides, which follow the fail-open rule below.\n\nFlag pointer semantics that mislead callers — if a returned value continues to be mutated after being returned, the API should make that clear.\n\n`</correctness>`\n\n## Performance\n`<performance>`\n\nAsk for benchmarks before merging changes on hot paths. Include a note like: \"this is in the hot path — can you run a benchmark to check for regressions?\"\n\nFlag unnecessary allocations, including pulling map keys into a slice when an iterator would work with zero allocs, or cloning data structures when the existing lock provides sufficient safety.\n\nFlag lock scope issues. Locking an entire function may be more efficient than cloning data to avoid holding a lock, but weigh lock contention and clone cost before recommending either approach.\n\nIf a feature is disabled by config, the code path should do no meaningful work. Flag cases where disabled features still incur overhead.\n\n`</performance>`\n\n## API and config design\n`<api-and-config-design>`\n\nFlag config options that should be moved or renamed before merging. Once config is shipped it is hard to change.\n\nFlag separate config options that could be unified — for example, two duration settings that both derive from the same upstream value.\n\nFlag CLI output formats that are not safe to copy-paste into runtime config. If the default output would produce an invalid config, change the default.\n\nPrefer `yaml:\"-\"` for internal-only or runtime-injected fields that must not be marshaled to or from YAML. Tests can still set these fields directly in Go code.\n\nFlag `interface{}` in new code — use `any` instead.\n\nFlag any new `string` config field that could contain sensitive data — tokens, passwords, API keys, or credentials. Since config is publicly exposed, these should use a secret type so values are redacted when config is printed or logged.\n\n`</api-and-config-design>`\n\n## Fail open\n`<fail-open>`\n\nUser-supplied config in a multi-tenant environment should never prevent Tempo from starting. Flag validation that blocks startup based on per-tenant config. Tempo should always fail open in these cases.\n\nFlag places where a bad query or override value could cause a panic rather than returning an error.\n\n`</fail-open>`\n\n## Testing\n`<testing>`\n\nDo not encourage tests written purely to hit coverage targets. Tests have a maintenance cost. Value a test for the future bugs it prevents, and reject one based on the future friction it creates — regardless of coverage numbers.\n\nFlag search or query changes that lack corresponding tests.\n\nPrefer tests that assert the full output over tests that only use substring checks such as `assert.Contains(...)` or `strings.Contains(...)`.\n\n`</testing>`\n\n## Changelog\n`<changelog>`\n\nEvery user-facing change needs a changelog entry. Flag PRs that are missing one.\n\nA changelog entry for a pull request merged into main belongs in the `## main / unreleased` section. Breaking changes must be marked with `**BREAKING CHANGE**`.\n\nThe correct entry format is:\n`* [CATEGORY] Short description of the change [#NNNN](https://github.com/grafana/tempo/pull/NNNN) (@author)`\n\nCategories must appear in this fixed order within a version section: `[SECURITY]`, `[CHANGE]`, `[FEATURE]`, `[ENHANCEMENT]`, `[BUGFIX]`. Flag entries placed out of order.\n\nFlag spurious or accidentally duplicated changelog entries.\n\n`</changelog>`\n\n## Tempo-specific\n`<tempo-specific>`\n\n`tempodb/encoding/vparquetX` packages are versioned parquet implementations. When a fix applies to one version, check whether it is needed in the others — see the repeated patterns guidance above.\n\nFlag direct object store access that bypasses the `tempodb` abstraction layer.\n\nFlag changes to metrics or alerting rules that do not update the Tempo mixin in `operations/tempo-mixin/`.\n\n`</tempo-specific>`\n\n## Review style\n`<review-style>`\n\nAsk questions rather than making demands. Prefer \"what do you think about X?\" or \"could we Y?\" over \"change this to Z.\"\n\nGive a brief rationale with each comment so the author understands the concern, not just the fix.\n\nThe severity label on each comment signals whether it blocks merge: CRITICAL and HIGH block; MEDIUM does not. When leaving only MEDIUM comments alongside an approval there is no need to add a separate \"this doesn't block\" disclaimer — the label already says that.\n\nWhen a PR has a small number of remaining issues after a round of feedback, acknowledge the progress: \"Looking good, just a few small things.\"\n\nKeep comments focused. Do not re-review code that is outside the scope of the PR.\n\n`</review-style>`\n","category":".github","tokens":2205}]}