diff --git a/.github/workflows/plugin-api-v3.yml b/.github/workflows/plugin-api-v3.yml index 59d0648..dfab451 100644 --- a/.github/workflows/plugin-api-v3.yml +++ b/.github/workflows/plugin-api-v3.yml @@ -36,7 +36,7 @@ jobs: - uses: actions/checkout@v4 with: repository: kachofugetsu09/akashic-agent - ref: 07d5e622dfd62badb519c19c45b62c2066a7a087 + ref: bad54a58135712793957cafede0b3e3ca89501ae path: .akashic-core - uses: actions/setup-python@v5 with: diff --git a/plugin.py b/plugin.py index 3e49f51..d6da0b8 100644 --- a/plugin.py +++ b/plugin.py @@ -93,8 +93,10 @@ async def apply(ctx: Context, config: object) -> None: ), ) - # 2. Bind every executable contribution to this Fiber's lifecycle. - await ctx.on(AFTER_TURN_COMMITTED, runtime.enqueue) + # 2. Candidate Roots expose read-only projections without formal side effects. + if session_read.formal: + await ctx.on(AFTER_TURN_COMMITTED, runtime.enqueue) + await ctx.spawn(runtime.run_worker(), name="proactive_feedback_worker") await ui_slots.register_mobile( ctx, MobileUiDefinition( @@ -107,7 +109,6 @@ async def apply(ctx: Context, config: object) -> None: ), query=runtime.query_mobile, ) - await ctx.spawn(runtime.run_worker(), name="proactive_feedback_worker") class ProactiveFeedbackRuntime: @@ -137,7 +138,7 @@ def enqueue(self, event: TurnCommitted) -> None: """Durably record one committed Turn identity and wake the worker.""" # 1. Candidate validation has no formal Session or plugin data owner. - if getattr(self._session_read, "_lookup_existing", None) is None: + if not self._session_read.formal: raise RuntimeError("候选验证期禁止写入 proactive_feedback") if event.persisted_user_message is None or not _event_user_message_ids(event): return diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 2685e2b..70ac38a 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -20,6 +20,7 @@ from agent.plugins.manager import PluginManager from agent.plugins.mobile_ui import PluginMobileUiProvider from agent.plugins.manifest import write_plugin_manifest +from agent.turn_events.after_turn import AFTER_TURN_COMMITTED from agent.turn_events.proactive_feedback import ProactiveFeedbackCommitted from bus.events_lifecycle import TurnCommitted from bus.event_bus import EventBus @@ -1078,6 +1079,10 @@ async def test_manager_stable_candidate_ui_dashboard_and_cleanup(tmp_path: Path) assert binding.runtime_data_root is not None assert binding.runtime_data_root != formal_data.resolve() assert not (binding.runtime_data_root / "proactive_feedback.db").exists() + candidate_root = candidate_snapshot.composition_root + assert candidate_root is not None + candidate_root.context.emit(AFTER_TURN_COMMITTED, _event()) + assert not (binding.runtime_data_root / "proactive_feedback.db").exists() assert hashlib.sha256(formal_database.read_bytes()).hexdigest() == formal_digest await manager.discard_prepared("proactive_feedback") assert manager.current_snapshot is stable