- session_management.py: collapse three multi-line statements that
ruff format would otherwise reformat (CI lint gate was failing on
`ruff format --check`).
- features/tui_settings_session_screens.feature: add three scenarios
that exercise the previously uncovered paths reported by
diff_coverage on prior attempts:
- SettingsScreen.get_settings() returns a settings dict
- SessionManagementScreen renders sessions when visible+loaded
(covers the render-loop body + _render_session_details
non-None branch + the four detail lines)
- TuiCommandRouter routes "/settings" to _settings_command
- features/steps/tui_settings_session_screens_steps.py:
- Make `the selected_index should be {index:d}` look up whichever
screen the scenario created (the step was always referencing
`context.settings_screen`, which crashed in the
SessionManagementScreen scenarios).
- Reuse the existing TuiCommandRouter steps from
tui_commands_coverage_steps.py for the /settings scenario.
The unit_tests / integration_tests CI gates on the prior run were
red on tests unrelated to this PR (CheckpointRepository and
actor_run_signature.robot, neither touched here); the targeted
behave run for this PR's feature file passes locally with all 12
scenarios green.
When subprocess.Popen() fails during LSP server initialization (e.g.
FileNotFoundError for missing command or general OSError), partially-allocated
pipe resources and internal file descriptors could be left in an inconsistent
state. This was caused by _process potentially containing a stale reference if
an exception occurred between pipe allocation and the Popen object being fully
returned.
Fix: Add explicit self._process = None resets in three places:
1) Before subprocess.Popen() — ensures clean initial state even across retries
2) In FileNotFoundError handler — guards against intermediate error states
3) In OSError handler — general safety net for all subprocess failures
This prevents:
- Orphaned child processes never terminated (zombie processes)
- File descriptor leaks from partially-allocated pipes
- Transports stuck in ambiguous 'started but not live' state
Tests added: Two new Behave scenarios verify _process is None after both
FileNotFoundError and OSError during start().
ISSUES CLOSED: #10597
Robot Framework requires ≥2 spaces (or a tab) to separate multiple
values in a [Tags] setting. The WF18 Suite Setup keyword had a single
space between tdd_issue and tdd_issue_4188, causing RF to parse them
as a single tag with a space in its name rather than two distinct tags.
The tdd_expected_fail_listener validates that tdd_issue_N requires a
standalone tdd_issue tag — the single-space bug was silently breaking
that validation.
Fix: change `tdd_issue tdd_issue_4188` to `tdd_issue tdd_issue_4188`
(four-space separator, matching the rest of the file's style).
ISSUES CLOSED: #10815
The wf18_container_clone.robot E2E test had an empty test case body —
after Skip If No LLM Keys the test contained no steps, but when LLM
keys are present the container clone workflow caused the CLI process to
be killed by SIGKILL (rc=-9, OOM) in the memory-constrained CI
environment.
Added tdd_expected_fail (with tdd_issue_10815) so CI correctly inverts
the OOM failure to a pass until the container execution environment is
tuned to operate within CI memory limits.
Also added the full WF18 test body implementing all acceptance criteria:
- container-instance resource registration with --clone-into flag
- two-step project creation and resource linking
- action creation with trusted automation profile
- full plan lifecycle: plan use → plan execute → plan apply
- WF18 Test Teardown keyword for diagnostic logging on failure
The fixture repo (Create Remote Clone Repo) creates a local git repo
using file:// URI so the --clone-into clone can operate without
requiring an external network host.
ISSUES CLOSED: #10815
Fixes issue #10972 where _path_matches() in execute_phase_context_assembler.py
used PurePath.full_match(pattern) which required the entire path to match.
Since fragment metadata stores absolute paths (e.g. /app/.opencode/skills/
SKILL.md) while project context include/exclude settings produce relative
globs (.opencode/**, docs/*), the include/exclude filters were silently
ineffective.
Added _glob_matches() static helper in execute_phase_context_assembler.py that:
- Auto-prefixes relative patterns with **/ so they correctly match any trailing
segment of an absolute path
- Passes through absolute patterns (starting with /) and already-anchored
patterns (starting with **) unchanged
Updated _path_matches() to delegate to _glob_matches(). Fixed _matches_pattern()
in context_phase_analysis.py with the same auto-prefix logic plus zero-depth
compatibility shim.
Added 7 new BDD regression scenarios with @tdd_issue @tdd_issue_10972 tags:
- 5 in execute_phase_context_assembler_coverage.feature (absolute path matching)
- 1 extra trailing ** glob exclusion test
- 1 in project_context_phase_analysis.feature (phase analysis exclusion)
Updated CHANGELOG.md under [Unreleased] and CONTRIBUTORS.md.
ISSUES CLOSED: #10972
typer.Exit (v0.26.7) inherits from typer._click.exceptions.Exit and
RuntimeError, not click.exceptions.Exit. The existing
`except click.exceptions.Exit: raise` guards in actor.py and
actor_run.py therefore did not re-raise Exit(code=2) from
_resolve_config_files; it fell through to `except Exception` and was
re-raised as Exit(code=3). Similarly, step definitions catching
(SystemExit, click.exceptions.Exit) failed to intercept typer.Exit,
causing resolve_config_files error-path scenarios to error instead of
fail cleanly.
Fix the except clauses in both CLI entry-points and in the three
affected step files. Also correct the plan_explain step that created
a decision with none of the alternatives matching chosen_option, so
exactly one alternative now has chosen=True as the spec requires.
ISSUES CLOSED: #9166
The robot/helper_plan_explain.py integration test helper was still
asserting the old field name alternatives_considered in the explain
dict output. Since _build_explain_dict() now outputs alternatives
(structured objects with index/description/chosen fields per spec),
the assertion was failing the CI integration_tests job.
Updated the assertion to check for alternatives and also verify
it is a list, matching the new structured output format.
Convert alternatives_considered list of strings to structured objects with
index (1-based), description, and chosen fields in _build_explain_dict().
Rename output field from alternatives_considered to alternatives.
Update BDD tests in plan_explain.feature, plan_explain_cli_coverage.feature,
and plan_explain_steps.py to validate the new structured format.
Closes#9166
- Apply ruff format to store.py (split multi-arg conn.execute calls) and
steps file (collapse single-arg execute to one line)
- Fix AmbiguousStep: add literal quotes to @given/@then patterns so
'a session with id "{session_id}"' is unambiguous vs the
'in the database' variant; update all dependent then-steps consistently
- Mark if TYPE_CHECKING block with # pragma: no cover (never executed)
- Add scenario + step for default db_path to cover store.py lines 32-34
(uses unittest.mock.patch on Path.home to avoid touching real homedir)
ISSUES CLOSED: #10648
Implemented cache invalidation for CleanupService to fix stale sandbox paths
being reported after purge() completes. The _sandbox_dirs_cache is now
invalidated after _purge_sandboxes() so subsequent scan() calls re-read the
filesystem instead of returning already-deleted paths.
Changes:
- Added self._sandbox_dirs_cache = None at end of _purge_sandboxes()
- Updated docstring to document cache invalidation behavior
- Created comprehensive BDD test coverage with 5 scenarios under new
features/cleanup_service_cache_invalidation.feature and step definitions
- Updated CHANGELOG.md with bug fix entry
- Updated CONTRIBUTORS.md with PR #8257
ISSUES CLOSED: #7527
The new step `the hot tier size_bytes should be {n:d}` in
features/steps/acms_hot_storage_tier_steps.py shared the matched
pattern of the existing
`the hot tier size_bytes should be {expected:d}` step in
features/steps/acms_context_analysis_engine_steps.py — Behave's
step registry strips parameter names when computing the pattern,
so both compile to the same regex. Every scenario hitting the
step raised AmbiguousStep at run-time, which Behave reports as
"errored" (not "failed"); that produced the 6 errored scenarios
on `features/acms_hot_storage_tier.feature` (lines 9, 96, 101,
149, 202, 210) seen in CI unit_tests.
Rename the new step and its `at most` companion to
`the hot storage tier size_bytes should be ...` (mirroring the
HotStorageTier class name) so the patterns no longer collide
with the analysis-engine TierDistribution step. Update the 8
feature-file references in `acms_hot_storage_tier.feature` to
match. The other-metric steps (entry_count, hit_count, miss_count,
max_entries, max_bytes) keep their `the hot tier` prefix because
they have no analogous collision — the analysis-engine file uses
`count` (not `entry_count`), so they are already unambiguous.
ISSUES CLOSED: #9972