Skip to content

feat(compaction): configurable keep-recent/truncation knobs on the compaction agent#857

Merged
dobesv merged 9 commits into
mainfrom
compaction-config
Jun 15, 2026
Merged

feat(compaction): configurable keep-recent/truncation knobs on the compaction agent#857
dobesv merged 9 commits into
mainfrom
compaction-config

Conversation

@dobesv

@dobesv dobesv commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary

Makes compaction's three tuning values configurable via the compaction agent's frontmatter only — no global setting, no calling-agent setting, no per-session override. The role is unambiguous: these fields only take effect when the agent is used as a compaction agent.

The built-in constants (renamed DEFAULT_*) remain the per-field fallback, so when no compaction_agent is configured — or one is configured but leaves a knob unset — behavior is unchanged.

New AgentConfig frontmatter fields (all Option<usize>)

Field Default
compaction_keep_recent_turns 3
compaction_keep_recent_tokens 8000
compaction_tool_output_max_chars 2000

Example compaction agent:

---
model: openai:gpt-4o
compaction_keep_recent_turns: 5
compaction_keep_recent_tokens: 12000
compaction_tool_output_max_chars: 500
---
You summarize prior conversation...

How it works

  • The three fields mirror the existing compaction_agent plumbing (struct field, from_markdown, AgentFrontMatter, from_config, is_empty, getter).
  • compaction.rs gains a CompactionParams struct and a compaction_params(&AgentConfig) resolver (per-field getter().unwrap_or(DEFAULT_*)).
  • compact_session is reordered so the summarizer agent is built before the read-lock snapshot block; its resolved params feed split_index (turns/tokens) and render_transcript (tool-output cap).
  • No compaction_agent → synthetic AgentConfig::from_prompt(DEFAULT_COMPACT_SYSTEM_PROMPT) → all knobs None → defaults → existing behavior preserved.

Testing

  • agent_config.rs: frontmatter parse + absent→None + serialize/reparse round-trip.
  • compaction.rs: compaction_params per-field override-then-default resolution.
  • tests.rs: end-to-end compact_session test proving compaction_keep_recent_turns: 1 keeps fewer turns verbatim than the default of 3.
  • Full pipeline green: cargo build, cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings, cargo nextest run --workspace --stress-count=5 (1541 passed × 5).

Out of scope (deliberate)

No global Config/settings.json/env wiring, no per-session override, no reading from the calling agent. DEFAULT_COMPACT_SYSTEM_PROMPT unchanged.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added optional per-agent compaction controls (recent turns, recent tokens, and tool output max chars) that can be set via agent configuration front-matter, with sensible defaults when unset.
    • Session compaction now applies the derived per-agent tuning when generating the compacted transcript.
  • Tests
    • Extended compaction test coverage to verify front-matter parsing/round-tripping and that recent-turn limits affect what gets forwarded to the LLM.

dobesv and others added 5 commits June 15, 2026 08:47
…tter

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ation

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on agent

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Three optional compaction tuning fields (compaction_keep_recent_turns, compaction_keep_recent_tokens, compaction_tool_output_max_chars) are added to AgentConfig with serde front-matter support. A new CompactionParams struct and compaction_params() resolver in the runtime crate resolve these per-agent overrides against renamed DEFAULT_* constants. compact_session is updated to derive params from the summarizer agent before rendering the transcript. Comprehensive test coverage including a new test module validates the parameter override precedence, fallback behavior, and end-to-end transcript compaction with agent-specific tuning.

Changes

Per-agent compaction knobs end-to-end

Layer / File(s) Summary
AgentConfig compaction fields, front-matter, and getters
crates/harnx-core/src/agent_config.rs
AgentConfig gains three Option<usize> compaction fields with serde skip_serializing_if. AgentFrontMatter is extended with matching fields; from_markdown, from_config, and is_empty are updated. Three public getter methods are added. A round-trip unit test covers Some/None parsing and export() fidelity.
CompactionParams struct and resolver
crates/harnx-runtime/src/config/compaction.rs
KEEP_*/TOOL_OUTPUT_MAX_CHARS constants are renamed to DEFAULT_*. A CompactionParams struct is introduced to hold resolved per-run values. compaction_params(agent) resolves all three fields from AgentConfig with DEFAULT_* fallbacks. A unit test verifies override precedence and fallback behavior per field.
compact_session integration with resolved parameters
crates/harnx-runtime/src/config/session_ops_split.rs
compact_session now constructs summarizer_agent and calls compaction_params() before acquiring transcript data. Prefix split calculation and transcript rendering use params fields instead of direct constants. Backward compatibility is preserved with synthetic default fallback.
Test infrastructure and comprehensive coverage
crates/harnx-runtime/src/config/mod.rs, crates/harnx-runtime/src/config/test_support.rs, crates/harnx-runtime/src/config/tests.rs, crates/harnx-runtime/src/config/compaction_tests.rs
Test module declarations added to mod.rs; EnvGuard RAII utility extracted into test_support.rs for environment variable management. New compaction_tests.rs module provides four async tests covering default compaction flow, rendered transcript with agent override, package-scoped agent resolution, and agent-specified keep_recent_turns behavior. Integration tests assert both rendered transcript content and session message counts reflect parameter overrides.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • dobesv/harnx#846: Directly precedes this PR — establishes the compaction split/flattening logic in compaction.rs and compact_session that this PR now parameterizes with per-agent overrides.
  • dobesv/harnx#288: Introduces the compaction-agent selection mechanism that this PR extends with per-agent tuning field support and parameter resolution.

Poem

🐇 Hop hop, the agent speaks,
"Keep one turn, that's all one seeks!"
CompactionParams bloom and grow,
From front-matter fields down below.
No more hardcoded fate — just DEFAULT_* and override great! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: introducing configurable compaction parameters (keep-recent/truncation knobs) for the compaction agent, which is the core objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch compaction-config

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.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/harnx-core/src/agent_config.rs (1)

601-619: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Refactor AgentFrontMatter::is_empty to clear the current quality gate failure.

Line 601 now carries an even longer boolean chain, and the added checks at Lines 616-618 increase method complexity in the same hotspot already failing CodeScene for this file. Please extract grouped predicates (for example, compaction-related emptiness) into helper methods to bring this method below the gate threshold.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/harnx-core/src/agent_config.rs` around lines 601 - 619, The is_empty
method in AgentFrontMatter has become too complex with a very long boolean
chain, especially after adding the compaction-related checks at lines 616-618,
causing a CodeScene quality gate failure. Extract logically grouped predicates
into separate private helper methods to reduce the method's cyclomatic
complexity. Specifically, create a helper method for compaction-related
emptiness checks (compaction_agent, compaction_keep_recent_turns,
compaction_keep_recent_tokens, and compaction_tool_output_max_chars), and
consider extracting other logical groupings such as model-related checks or
conversation-related checks into their own helper methods. Replace the
corresponding conditions in is_empty with calls to these new helper methods to
bring the method below the complexity threshold.

Source: Pipeline failures

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/harnx-runtime/src/config/tests.rs`:
- Around line 617-714: Extract helper functions from the
test_compact_session_honors_compaction_keep_recent_turns test to reduce its size
and assertion density. Create a setup helper that encapsulates the creation of
the temporary directory, agent files, main agent configuration, session with
four turns, and mock client setup (everything from the start through
TestStateGuard creation). Create separate assertion helpers for each major
assertion block: one helper to verify the conversation history contains the
expected compacted transcript with the first three user turns but not the
fourth, and another helper to verify the session messages contain the summary
plus the two kept verbatim messages. Replace the inline setup and assertion code
in the test with calls to these helpers so the main test function becomes
concise and focused on orchestrating the test flow.
- Around line 622-629: The test function uses blocking std::fs operations which
violates the project guideline requiring Tokio async I/O in async tests. Replace
std::fs::create_dir_all with tokio::fs::create_dir_all and std::fs::File::create
with tokio::fs::File::create, then use tokio::io::AsyncWriteExt to perform the
async write operation. Ensure all these filesystem operations are awaited since
the test is async.

---

Outside diff comments:
In `@crates/harnx-core/src/agent_config.rs`:
- Around line 601-619: The is_empty method in AgentFrontMatter has become too
complex with a very long boolean chain, especially after adding the
compaction-related checks at lines 616-618, causing a CodeScene quality gate
failure. Extract logically grouped predicates into separate private helper
methods to reduce the method's cyclomatic complexity. Specifically, create a
helper method for compaction-related emptiness checks (compaction_agent,
compaction_keep_recent_turns, compaction_keep_recent_tokens, and
compaction_tool_output_max_chars), and consider extracting other logical
groupings such as model-related checks or conversation-related checks into their
own helper methods. Replace the corresponding conditions in is_empty with calls
to these new helper methods to bring the method below the complexity threshold.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db9ff911-965b-44ef-b37a-cb7704f6a19e

📥 Commits

Reviewing files that changed from the base of the PR and between bc933b4 and aeadbfc.

📒 Files selected for processing (4)
  • crates/harnx-core/src/agent_config.rs
  • crates/harnx-runtime/src/config/compaction.rs
  • crates/harnx-runtime/src/config/session_ops_split.rs
  • crates/harnx-runtime/src/config/tests.rs

Comment thread crates/harnx-runtime/src/config/tests.rs Outdated
Comment thread crates/harnx-runtime/src/config/tests.rs Outdated
…pers

Address CodeScene complexity on AgentFrontMatter::is_empty by grouping the
boolean chain into model/content/compaction helpers, and extract the
keep-recent-turns compaction test into a setup fixture plus two assertion
helpers to lower its size and assertion density.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

…ion density

The earlier helper extraction added net lines and concentrated assertions into
a single helper, which CodeScene flags as a new large assertion block and
worsens this file's lines-of-code. Inline the test instead and spread its
assertions (max two consecutive), keeping the same end-to-end coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

Move the compact_session tests and their helper out of the oversized
config/tests.rs into config/compaction_tests.rs, and share EnvGuard via a
new config/test_support.rs. Reduces tests.rs lines-of-code, responsibilities,
and assertion-block count to improve CodeScene health; behavior unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

Pull the temp-dir/agent-file/config/session/mock setup into shared helpers so
each compact_session test drops below CodeScene's 70-line Large Method
threshold, and the tests share helpers (raising the module's cohesion).
Behavior and assertions unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/harnx-runtime/src/config/compaction_tests.rs (1)

15-21: 💤 Low value

Sync I/O in test helper may violate the async-everywhere guideline.

The write_agent helper uses std::fs::create_dir_all and std::fs::File::create (synchronous I/O), but the coding guidelines state "All I/O must be async via Tokio using async fn and .await." While test utilities often use sync I/O for simplicity, verify whether the project's strict async policy applies to test code.

♻️ Optional refactor to use async I/O
-fn write_agent(dir: &std::path::Path, name: &str, content: &str) {
-    std::fs::create_dir_all(dir).unwrap();
-    std::fs::File::create(dir.join(format!("{name}.md")))
-        .unwrap()
-        .write_all(content.as_bytes())
-        .unwrap();
+async fn write_agent(dir: &std::path::Path, name: &str, content: &str) {
+    tokio::fs::create_dir_all(dir).await.unwrap();
+    tokio::fs::write(dir.join(format!("{name}.md")), content.as_bytes())
+        .await
+        .unwrap();
 }

Then call with .await from test functions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/harnx-runtime/src/config/compaction_tests.rs` around lines 15 - 21,
The write_agent helper function uses synchronous I/O operations
(std::fs::create_dir_all and std::fs::File::create) which conflicts with the
project's async-everywhere guideline requiring all I/O to be performed via Tokio
with async fn and await. Convert the write_agent function to an async function,
replace the synchronous file system calls with their Tokio async equivalents
(tokio::fs::create_dir_all and tokio::fs::File), update the write_all call to
use Tokio's async write method, and ensure all call sites of write_agent are
updated to use await when invoking the function.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/harnx-runtime/src/config/test_support.rs`:
- Around line 12-27: The test functions
`info_theme_reports_custom_theme_path_and_name` and
`info_theme_reports_custom_theme_without_name` invoke `EnvGuard::new()` without
acquiring the required global test lock, violating the safety contract
documented in the `EnvGuard` implementation. Fix this by acquiring the lock
(using `env_lock()` or similar synchronization mechanism) before instantiating
`EnvGuard` in both test functions, storing the lock guard to keep it alive for
the duration of the test. Alternatively, refactor `EnvGuard::new()` to accept a
reference to a lock guard (such as `&TestStateGuard`) as a parameter, making the
lock requirement compile-time enforced.

---

Nitpick comments:
In `@crates/harnx-runtime/src/config/compaction_tests.rs`:
- Around line 15-21: The write_agent helper function uses synchronous I/O
operations (std::fs::create_dir_all and std::fs::File::create) which conflicts
with the project's async-everywhere guideline requiring all I/O to be performed
via Tokio with async fn and await. Convert the write_agent function to an async
function, replace the synchronous file system calls with their Tokio async
equivalents (tokio::fs::create_dir_all and tokio::fs::File), update the
write_all call to use Tokio's async write method, and ensure all call sites of
write_agent are updated to use await when invoking the function.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9f8ebc1c-37a8-419a-b734-120bed892792

📥 Commits

Reviewing files that changed from the base of the PR and between aeadbfc and 9bbcb38.

📒 Files selected for processing (5)
  • crates/harnx-core/src/agent_config.rs
  • crates/harnx-runtime/src/config/compaction_tests.rs
  • crates/harnx-runtime/src/config/mod.rs
  • crates/harnx-runtime/src/config/test_support.rs
  • crates/harnx-runtime/src/config/tests.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/harnx-core/src/agent_config.rs
  • crates/harnx-runtime/src/config/tests.rs

Comment on lines +12 to +27
pub(super) fn new(key: &'static str, value: &std::path::Path) -> Self {
let prev = std::env::var_os(key);
// SAFETY: test-only; concurrent env mutation is prevented by the
// global test lock held by the caller while the guard is alive.
unsafe { std::env::set_var(key, value) };
Self { key, prev }
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
match &self.prev {
Some(v) => unsafe { std::env::set_var(self.key, v) },
None => unsafe { std::env::remove_var(self.key) },
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify EnvGuard is only instantiated while TestStateGuard is held.

# Search for EnvGuard::new call sites
echo "=== EnvGuard::new call sites ==="
rg -n -A5 -B5 'EnvGuard::new' --type rust

# Search for patterns where EnvGuard might be used without guard
echo "=== Checking for TestStateGuard in same scope ==="
rg -n -B10 'EnvGuard::new' --type rust | rg -C3 'TestStateGuard'

Repository: dobesv/harnx

Length of output: 50368


🏁 Script executed:

# Check EnvGuard implementation in test_support.rs
head -50 crates/harnx-runtime/src/config/test_support.rs

Repository: dobesv/harnx

Length of output: 1020


🏁 Script executed:

# Check the tokio::test call sites in commands.rs more carefully
sed -n '1330,1410p' crates/harnx-runtime/src/commands.rs

Repository: dobesv/harnx

Length of output: 2534


🏁 Script executed:

# Check if there's a TestStateGuard and how it's defined
rg -n 'struct TestStateGuard' --type rust

Repository: dobesv/harnx

Length of output: 130


🏁 Script executed:

# Check if tests in commands.rs are somehow isolated/serialized
rg -n -B2 'info_theme_reports_custom_theme' crates/harnx-runtime/src/commands.rs | head -30

Repository: dobesv/harnx

Length of output: 340


🏁 Script executed:

# Check what env_lock is and how it works
rg -n 'fn env_lock' --type rust -A5

Repository: dobesv/harnx

Length of output: 2564


🏁 Script executed:

# Check TestStateGuard implementation
sed -n '44,100p' crates/harnx-runtime/src/client/mod.rs

Repository: dobesv/harnx

Length of output: 1698


🏁 Script executed:

# Check if there's a test harness or something that enforces serial execution
rg -n 'serial|SERIAL|Mutex|test_lock' crates/harnx-runtime/src/commands.rs

Repository: dobesv/harnx

Length of output: 919


🏁 Script executed:

# Check if any other async test in the codebase uses EnvGuard without a lock
rg -n 'async fn.*test' crates/harnx-runtime/src/commands.rs | head -20

Repository: dobesv/harnx

Length of output: 177


🏁 Script executed:

# Let's check if there's a global lock mechanism in the test module
rg -n 'lazy_static|once_cell|static.*LOCK|static.*MUTEX' crates/harnx-runtime/src/commands.rs

Repository: dobesv/harnx

Length of output: 38


🏁 Script executed:

# Double-check: are env_lock() calls in commands.rs at all?
rg -n 'env_lock' crates/harnx-runtime/src/commands.rs

Repository: dobesv/harnx

Length of output: 38


🏁 Script executed:

# Let's see the full context around the two problem test functions
sed -n '1332,1345p' crates/harnx-runtime/src/commands.rs
sed -n '1402,1415p' crates/harnx-runtime/src/commands.rs

Repository: dobesv/harnx

Length of output: 1247


🏁 Script executed:

# Check if there's any ENV_MUTEX in commands.rs module
rg -n 'ENV_MUTEX|LOCK' crates/harnx-runtime/src/commands.rs | head -20

Repository: dobesv/harnx

Length of output: 38


🏁 Script executed:

# Verify: how many test functions use EnvGuard in commands.rs without visible lock?
rg -B5 'EnvGuard::new.*HARNX_CONFIG_DIR' crates/harnx-runtime/src/commands.rs | rg -E '(async fn|let _lock|let _guard|env_lock)'

Repository: dobesv/harnx

Length of output: 453


🏁 Script executed:

# Check if commands.rs has any module-level test setup or teardown
grep -n '#\[cfg(test)\]' crates/harnx-runtime/src/commands.rs

Repository: dobesv/harnx

Length of output: 74


🏁 Script executed:

# Look for all #[tokio::test] tests in commands.rs and check if any hold locks
rg -n '#\[tokio::test\]' crates/harnx-runtime/src/commands.rs -A10 | grep -E '(tokio::test|let _|env_lock|LOCK|MUTEX|Guard)' | head -40

Repository: dobesv/harnx

Length of output: 344


🏁 Script executed:

# Count EnvGuard calls in commands.rs vs calls with locks visible
echo "=== EnvGuard calls in commands.rs ==="
rg -c 'EnvGuard::new' crates/harnx-runtime/src/commands.rs || echo "0"
echo ""
echo "=== Context around these calls ==="
rg -B10 'EnvGuard::new' crates/harnx-runtime/src/commands.rs | grep -E '(fn |let _lock|env_lock|LOCK)'

Repository: dobesv/harnx

Length of output: 257


🏁 Script executed:

# Check if tokio::test provides implicit serialization or isolation
rg -n 'tokio::test' crates/harnx-runtime/src/commands.rs | wc -l

Repository: dobesv/harnx

Length of output: 58


Two EnvGuard instantiations in commands.rs omit the required lock, creating potential data races.

The tests info_theme_reports_custom_theme_path_and_name and info_theme_reports_custom_theme_without_name (lines 1335, 1405) call EnvGuard::new() without holding the global test lock. The EnvGuard documentation explicitly requires "callers must hold the global test lock while it is alive," but these #[tokio::test] functions have no lock acquisition visible in their scope.

Most other call sites (in harnx-runtime/tests/package_loading.rs, harnx-sandbox-common/, etc.) correctly hold env_lock(), ENV_MUTEX, or TestStateGuard before instantiating EnvGuard. The pattern works in practice because test harnesses often serialize, but it remains fragile without type-system enforcement.

Acquire the lock before EnvGuard::new():

let _lock = env_lock(); // or similar synchronization
let _env = EnvGuard::new("HARNX_CONFIG_DIR", temp.path());

Alternatively, refactor EnvGuard::new to require a &TestStateGuard parameter, making the lock requirement compile-time enforced.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/harnx-runtime/src/config/test_support.rs` around lines 12 - 27, The
test functions `info_theme_reports_custom_theme_path_and_name` and
`info_theme_reports_custom_theme_without_name` invoke `EnvGuard::new()` without
acquiring the required global test lock, violating the safety contract
documented in the `EnvGuard` implementation. Fix this by acquiring the lock
(using `env_lock()` or similar synchronization mechanism) before instantiating
`EnvGuard` in both test functions, storing the lock guard to keep it alive for
the duration of the test. Alternatively, refactor `EnvGuard::new()` to accept a
reference to a lock guard (such as `&TestStateGuard`) as a parameter, making the
lock requirement compile-time enforced.

@dobesv dobesv merged commit 7abb039 into main Jun 15, 2026
8 checks passed
@dobesv dobesv deleted the compaction-config branch June 15, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant