Skip to content

feat(session)!: persist watch and connect rules - #196

Merged
BegoniaHe merged 7 commits into
masterfrom
feat/persist-session-bridge-193
Sep 15, 2026
Merged

BegoniaHe merged 7 commits into
masterfrom
feat/persist-session-bridge-193

Conversation

@BegoniaHe

Copy link
Copy Markdown
Member

Summary

Persist /session watch and /session connect as directed SQLite edges with stable rule_ids, wall-clock watch TTL (floor 1 second), and IM /session links / /session unlink for creators and same-config operators.

Related issue

Fixes #193
Related: #192

Behavior

  • Unexpired watches and all connects survive process restart; expired watches are deleted and notify the listener.
  • Watch duration is 1–864000 seconds on the wall clock; connect stays unbounded and rejects extra tokens.
  • Same-direction watch recreate keeps rule_id and resets TTL; connect retarget is 1:1; watch↔connect replace each other.
  • /session links and /session unlink <rule_id> are IM-only. Creators see and can revoke their own rules after role loss; current-config instance_operator sees/revokes rules touching that config; operator/root see and revoke all.
  • SessionWatch now has rule_id; expires_at is wall-clock UTC unix seconds; list() still returns only the actor's watches.

Non-goals

  • pair / unpair (#194)
  • /session filter (#195)
  • Dashboard / OpenAPI CRUD
  • Connect TTL
  • Extending SessionBridgeCapability with links/unlink

Implementation notes

SessionBridgeManager remains the public owner. Live grants, connect 1:1, and store IO live in private SessionBridgeState. The new session_bridge_rules table includes S2/S3 columns (pair_id, match, except, header) written with S1 defaults. Restore rebuilds Subject.from_id and re-authorizes; lost permission deletes the row. Adapter-unavailable deliveries skip without deleting the rule.

This is a plugin SDK semantic break for SessionWatch and MIN_WATCH_TTL_SECONDS.

Validation

uv run ruff check <touched python>
uv run pytest tests/unit/db/test_session_bridge_store.py tests/unit/db/test_schema.py tests/unit/db/test_protocols.py tests/unit/test_session_bridge.py tests/unit/test_session_commands.py tests/unit/test_message_protocol.py tests/unit/test_core_lifecycle.py tests/unit/test_builtin_command_extensions.py::test_non_public_builtin_commands_declare_the_planned_actions
make check-md

Not run: make check, make test-blocking.

Compatibility and risk

Breaking for plugins that assume monotonic SessionWatch.expires_at or MIN_WATCH_TTL_SECONDS == 60. Restore AuthContext is reconstructed from subject.kind without a new column; deny deletes the row (fail closed). No OpenAPI change.

Checklist

  • A Feature request Issue exists for large work, or this is a small, obvious addition.
  • The change is focused and does not include unrelated refactoring.
  • I added or updated tests, or explained why tests are not practical.
  • User-visible behavior updates both docs/zh/ and docs/en/.
  • OpenAPI, generated client, docs/public/openapi.json, and tests change together when routes or schemas change.
  • No secrets committed. Runtime Python deps update pyproject.toml, requirements.txt, and uv.lock together.
  • I did not restore legacy shims, Python <3.14 fallbacks, or upstream publish/docs URLs as fork artifacts.
  • Breaking API or behavior changes use ! and a BREAKING CHANGE: footer.
  • I will not merge this PR myself. Merge needs a human maintainer review plus a separate AI-assisted review (AI_POLICY.md).
  • AI use follows AI_POLICY.md. Keep exactly one author note below. Do not fabricate the other.

Agent note

Goal: ship #193 S1 of the session-bridge persistence stack. Paths: new session_bridge_rules store, SessionBridgeState, manager restore/lifecycle, IM links/unlink, bilingual command/authorization/send-message docs. Checks actually run are listed under Validation; make check and blocking pytest were not run. Residual risk: reconstructed restore context for rare subject kinds, and the SDK wall-clock/rule_id break. Tools: OpenCode / grok-4.6.

Register a directed-edge SQLModel table with S2/S3 columns so later
slices fill fields without altering schema.

Related: #193
AI-Generated: true
Generated-At: 2026-09-15T00:38:58Z
Store directed edges in SQLite, restore and re-authorize on startup,
and lower the watch floor to 1 second. Extract SessionBridgeState as
the live index.

BREAKING CHANGE: SessionWatch.expires_at is wall-clock UTC unix seconds
and now includes rule_id. MIN_WATCH_TTL_SECONDS is 1. remaining_seconds
no longer uses monotonic time.

Related: #193
AI-Generated: true
Generated-At: 2026-09-15T00:39:47Z
Let creators and same-config operators list and revoke persisted
watch/connect edges by stable rule_id.

Related: #193
AI-Generated: true
Generated-At: 2026-09-15T00:40:08Z
Record wall-clock TTL, SQLite persistence, connect without duration,
and IM-only links/unlink in zh and en docs.

Fixes #193
AI-Generated: true
Generated-At: 2026-09-15T00:40:27Z
@BegoniaHe BegoniaHe self-assigned this Sep 15, 2026
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Comment thread astrbot/core/db/protocols.py Fixed
Replace SessionBridgeStore protocol ellipsis bodies so CodeQL does
not flag ineffectual statements. Type expiry tasks as coroutines for
pyright. Check watch/connect limits before deleting an existing edge,
skip pair rows on restore, fail closed on invalid restore rows, and
hide expired watches from /session links.

Related: #193
AI-Generated: true
Generated-At: 2026-09-15T00:58:46Z
Comment thread astrbot/core/platform/session_bridge.py Fixed
Replace the empty restore except with a log, keep later rules when
authorize raises unexpectedly, refresh stored config ids, skip
unavailable listeners, and translate link TTL labels.

Related: #193
AI-Generated: true
Generated-At: 2026-09-15T01:15:05Z
Update the grouped CLI name test for links/unlink. Store expiry as
ceil(now+ttl) so a 1-second watch is not already elapsed. Drop extra
connects for the same listener on restore and remove unused state
helpers.

Related: #193
AI-Generated: true
Generated-At: 2026-09-15T01:44:37Z
@BegoniaHe
BegoniaHe merged commit 3fe688b into master Sep 15, 2026
26 checks passed
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.

[feat] persist session-bridge watch and connect rules

2 participants