Skip to content

session: remove legacy teardown aliases - #413

Merged
yisding merged 2 commits into
mainfrom
agent/session-lifecycle-single-api
Jul 11, 2026
Merged

session: remove legacy teardown aliases#413
yisding merged 2 commits into
mainfrom
agent/session-lifecycle-single-api

Conversation

@yisding

@yisding yisding commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Problem

Session exposed four teardown vocabularies: stop(), shutdown(), close(), and destroy(), plus two low-level wrapper names (_close() / _destroy()). The deprecated aliases preserved ambiguity over cancellation strategy, clean-close markers, physical backend teardown, and whether post-stop inspection remained valid.

EasyCat is still pre-release, so retaining these compatibility paths costs more architectural clarity than it provides.

Changes

  • Remove Session.shutdown(), Session.close(), and Session.destroy().
  • Remove the redundant Session._close() and Session._destroy() wrappers.
  • Make stop(force=False|True) the single public teardown verb.
  • Rename the sole internal tail to _finalize_debug_backends() to describe its ownership.
  • Keep graceful and forceful paths converged on identical backend finalization and read-only postmortem preservation.
  • Move finalize/close retry tests from obsolete Session aliases to the owning SessionDebugBackends collaborator.
  • Update README, lifecycle reference, durability contract, teaching chapter, public API policy, AGENTS.md, CLAUDE.md, and their guard tests.

Breaking change

Callers must replace:

  • await session.shutdown() with await session.stop(force=True)
  • session.close() / session.destroy() with await session.stop() or async with session:

There is intentionally no compatibility alias during the pre-release period.

Validation

  • ruff format --check .
  • ruff check .
  • 157 focused lifecycle, debug-backend, journal, docs-route, teaching, and public-API tests passed
  • 171 contributor, agent-guide, docs, teaching, deprecation, DX, and public-API guard tests passed
  • Changed source modules pass mypy with site-package stubs excluded
  • Teaching chapter generated blocks are current

A local all-tests/session serial run reached an unrelated executor-using session-action test and hit the existing Python 3.12.13 default-executor fixture-teardown hang. The directly affected suites pass; repository CI provides the clean-environment full validation.

Summary by CodeRabbit

  • Breaking Changes
    • Removed deprecated session teardown methods: shutdown(), close(), and destroy().
  • Documentation
    • Updated session lifecycle guidance to make await session.stop() the single public teardown entry point (including force semantics and async with behavior).
    • Clarified that the journal remains readable and debug bundles can be exported after stopping.
    • Updated deprecation/removal policy and legacy settings= vs params= guidance.
  • Tests
    • Added/updated coverage for debug backend finalize/close/destroy retry behavior and aligned lifecycle/deprecation expectations.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 033bb6c2-efc2-468c-94ce-de608754ee0b

📥 Commits

Reviewing files that changed from the base of the PR and between d984d3b and c18898d.

📒 Files selected for processing (6)
  • docs/teaching/15-operate-in-production/EXERCISES.md
  • src/easycat/integrations/agents/llama_agents.py
  • src/easycat/session/_audio_router.py
  • tests/docs/test_route_contracts.py
  • tests/session/test_session_lifecycle_teardown.py
  • tests/test_public_api.py

📝 Walkthrough

Walkthrough

Session teardown was consolidated around stop(force=...), deprecated aliases were removed, backend finalization was centralized, post-stop journal behavior was preserved, and documentation and tests were updated to match the revised lifecycle and deprecation contracts.

Changes

Session teardown contract

Layer / File(s) Summary
Backend finalization path
src/easycat/session/_session.py, src/easycat/runtime/DURABILITY.md, src/easycat/_provider_helpers.py, src/easycat/transports/_base.py, docs/reference/session-lifecycle.md, src/easycat/integrations/agents/llama_agents.py, src/easycat/session/_audio_router.py
stop() now uses _finalize_debug_backends(), removes deprecated teardown aliases, finalizes journal and backend resources, and preserves a read-only post-stop view.
Teardown and retry validation
tests/session/*
Lifecycle tests now use stop(force=...), verify removed aliases, and cover retry behavior after journal or backend failures.
Lifecycle documentation and policy alignment
AGENTS.md, CLAUDE.md, README.md, docs/public-api.md, docs/teaching/15-operate-in-production/*, tests/docs/*, tests/teaching/*, tests/test_dx_helpers.py, tests/test_deprecations.py, tests/test_public_api.py
Guidance, teaching material, deprecation policy, and contract tests now describe stop(), force semantics, postmortem access, pre-release removal, and settings= warnings without legacy aliases.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Session
  participant SessionDebugBackends
  participant Journal
  participant BackendStores
  Session->>SessionDebugBackends: _finalize_debug_backends()
  SessionDebugBackends->>Journal: write clean-close marker
  SessionDebugBackends->>BackendStores: close backend resources
  SessionDebugBackends-->>Session: preserve read-only postmortem view
Loading

Possibly related PRs

  • yisding/easycat#390: Touches the same session teardown aliases and stop() lifecycle behavior.
  • yisding/easycat#402: Updates the same DX lifecycle evidence around the deprecated Session.shutdown alias.

Poem

I’m a rabbit hopping through the stop,
No shutdown aliases left to crop.
Journals rest, read-only and bright,
Backends close in tidy flight.
force=True makes the final leap!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.47% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: removing legacy session teardown aliases.
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.
✨ 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 agent/session-lifecycle-single-api

Comment @coderabbitai help to get the list of available commands.

@charliecreates charliecreates Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed the lifecycle teardown consolidation and its repository references. The context-manager force-stop behavior, unified backend finalization, read-only post-stop inspection, and retry coverage are aligned with the new single-verb API. No blocking findings.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (3)
tests/docs/test_route_contracts.py (1)

181-189: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert that removed lifecycle aliases are absent from the reference page.

The new positive marker only proves that the replacement text exists; stale shutdown(), close(), or destroy() examples could remain and the test would still pass.

Proposed assertions
     for marker in (
         "`stop(force=True)`",
         "There are no separate public close/destroy phases",
         "`session.journal.read()`",
         "`session.export_debug_bundle(path)`",
         "`async with session:`",
         "record_to",
     ):
         assert marker in text, f"docs/reference/session-lifecycle.md missing {marker!r}"

+    for stale in (
+        "session.shutdown()",
+        "Session.shutdown()",
+        "session.close()",
+        "Session.close()",
+        "session.destroy()",
+        "Session.destroy()",
+    ):
+        assert stale not in text

As per coding guidelines, add or update tests for every behavior change.

🤖 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 `@tests/docs/test_route_contracts.py` around lines 181 - 189, Update the
lifecycle documentation contract test around the marker loop to also assert that
removed aliases and examples—such as `shutdown()`, `close()`, and
`destroy()`—are absent from the reference page, while retaining the existing
positive marker checks.

Source: Coding guidelines

tests/test_public_api.py (1)

222-234: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Protect the machine-visible deprecation guarantee.

docs/public-api.md still states that stable symbols normally carry a machine-visible deprecation signal, but this contract test does not assert that wording. A future edit could weaken that guarantee while all current assertions still pass.

Proposed test assertions
     assert "`settings=`" in section
+    assert "machine-visible deprecation signal" in section
     assert "pre-release" in section
     assert "ownership ambiguity" in section
+    assert "params=" in section

As per coding guidelines, add or update tests for every behavior change.

🤖 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 `@tests/test_public_api.py` around lines 222 - 234, Update
test_public_api_documents_deprecation_and_removal_policy to assert that the
Deprecation & Removal Policy section explicitly states the machine-visible
deprecation signal guarantee for stable symbols. Add an assertion matching the
documented wording, alongside the existing settings, pre-release, and ownership
ambiguity checks.

Source: Coding guidelines

src/easycat/session/_session.py (1)

1212-1226: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Session-level retry contract for backend finalization failure is untested.

_finalize_debug_backends() documents itself as "safe to call multiple times," which holds at the SessionDebugBackends.destroy() level (guarded by _destroyed, verified by the new test_debug_backends_destroy_retries_after_backend_close_failure). However, if destroy() raises inside stop() (line 1194), the exception propagates past self._mark_closed() (line 1195) without being caught, leaving _closed=False while _stopping is still reset to False in the finally block. A caller must know to retry stop() itself to eventually flip _closed and unblock wait_closed() waiters — this full-stop() retry path (as opposed to the isolated SessionDebugBackends retry) isn't exercised by any test in this changeset.

Given this PR is establishing stop(force=...) as the sole, guaranteed teardown contract, an integration test that forces _finalize_debug_backends() to fail once (e.g. via a TrackingJournal subclass like the ones in test_debug_backends.py) and asserts that a second await session.stop() succeeds and unblocks wait_closed() would close this coverage gap.

Do you want me to draft this test?

🤖 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 `@src/easycat/session/_session.py` around lines 1212 - 1226, Add an integration
test covering the full Session.stop() retry contract: force
_finalize_debug_backends() to fail once using a tracking backend/journal
fixture, assert the first stop raises while the session remains open, then
verify a second await session.stop() succeeds, marks the session closed, and
unblocks wait_closed().
🤖 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.

Outside diff comments:
In `@src/easycat/session/_session.py`:
- Around line 1212-1226: Add an integration test covering the full
Session.stop() retry contract: force _finalize_debug_backends() to fail once
using a tracking backend/journal fixture, assert the first stop raises while the
session remains open, then verify a second await session.stop() succeeds, marks
the session closed, and unblocks wait_closed().

In `@tests/docs/test_route_contracts.py`:
- Around line 181-189: Update the lifecycle documentation contract test around
the marker loop to also assert that removed aliases and examples—such as
`shutdown()`, `close()`, and `destroy()`—are absent from the reference page,
while retaining the existing positive marker checks.

In `@tests/test_public_api.py`:
- Around line 222-234: Update
test_public_api_documents_deprecation_and_removal_policy to assert that the
Deprecation & Removal Policy section explicitly states the machine-visible
deprecation signal guarantee for stable symbols. Add an assertion matching the
documented wording, alongside the existing settings, pre-release, and ownership
ambiguity checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8a9e064e-af1a-4fc8-a5fb-b038e5ec264d

📥 Commits

Reviewing files that changed from the base of the PR and between 8b5e14e and d984d3b.

📒 Files selected for processing (21)
  • AGENTS.md
  • CLAUDE.md
  • README.md
  • docs/public-api.md
  • docs/reference/session-lifecycle.md
  • docs/teaching/15-operate-in-production/README.md
  • docs/teaching/15-operate-in-production/main.py
  • src/easycat/_provider_helpers.py
  • src/easycat/runtime/DURABILITY.md
  • src/easycat/session/_session.py
  • src/easycat/transports/_base.py
  • tests/docs/test_route_contracts.py
  • tests/session/test_debug_backends.py
  • tests/session/test_journal_sink.py
  • tests/session/test_record_to.py
  • tests/session/test_session_journal_accounting.py
  • tests/session/test_session_lifecycle_teardown.py
  • tests/teaching/test_ladder_index.py
  • tests/test_deprecations.py
  • tests/test_dx_helpers.py
  • tests/test_public_api.py

@yisding

yisding commented Jul 11, 2026

Copy link
Copy Markdown
Owner Author

Review findings — three references to the removed aliases survived the sweep:

  1. docs/teaching/15-operate-in-production/EXERCISES.md:82 — the self-check still asks learners to "explain when to use … the shutdown() compatibility alias", which this PR removes.
  2. src/easycat/session/_audio_router.py:584 — comment says "Session's stop()/shutdown() handles full cleanup." — shutdown() is gone.
  3. src/easycat/integrations/agents/llama_agents.py:325aclose() docstring says "Session.stop()/shutdown() call aclose_if_supported(self.agent)…" — same.

Everything else checked out: CLAUDE.md / AGENTS.md / session-lifecycle reference / DURABILITY.md / README / public-api docs are all updated, no functional callers of the removed methods remain anywhere in the tree, and the stop()-only surface is pinned by the new regression assertions.

Comment thread tests/session/test_debug_backends.py
@yisding
yisding merged commit 1ce541e into main Jul 11, 2026
17 checks passed
@yisding
yisding deleted the agent/session-lifecycle-single-api branch July 11, 2026 23:16
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