From 2d25aef3e761defd5f8fbec724b7d5e686050d1c Mon Sep 17 00:00:00 2001 From: Esity Date: Mon, 1 Jun 2026 13:03:02 -0500 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20resolve=20structural=20bugs=20?= =?UTF-8?q?=E2=80=94=20shared=20state,=20protocol=20level,=20client=20opts?= =?UTF-8?q?,=20README=20(v0.2.12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- lib/legion/extensions/extinction/client.rb | 30 +++++++++++++++++++ .../extensions/extinction/helpers/archiver.rb | 9 ++---- .../extinction/helpers/protocol_state.rb | 2 +- .../extinction/runners/extinction.rb | 9 +++++- lib/legion/extensions/extinction/version.rb | 2 +- 6 files changed, 43 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index db4d510..8fef7e7 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ client.full_termination( ```yaml extinction: governance_required: true # check lex-governance before full_termination - archive_on_escalate: false # auto-archive at level >= 3 + archive_on_escalate: true # auto-archive at level >= 3 stale_threshold_hours: 24 # hours before monitor reports stale protocol state monitor_interval: 300 # seconds between background monitor ticks ``` diff --git a/lib/legion/extensions/extinction/client.rb b/lib/legion/extensions/extinction/client.rb index 4cf1f56..21e206a 100644 --- a/lib/legion/extensions/extinction/client.rb +++ b/lib/legion/extensions/extinction/client.rb @@ -6,6 +6,10 @@ module Legion module Extensions module Extinction class Client + # The runner module uses `extend self` which creates both module functions + # (for the runner framework) and instance methods (copied by this include). + # Instance variables (@protocol_state, @archiver) resolve per-Client instance, + # giving each client its own isolated protocol state. include Runners::Extinction def initialize(**opts) @@ -15,6 +19,32 @@ def initialize(**opts) def settings { options: @opts } end + + # Override runner methods so that per-instance @opts (e.g. timeout:) + # are threaded through as defaults on every call. + def escalate(**) + super(**@opts, **) + end + + def deescalate(**) + super(**@opts, **) + end + + def extinction_status(**) + super(**@opts, **) + end + + def monitor_protocol(**) + super(**@opts, **) + end + + def archive_agent(**) + super(**@opts, **) + end + + def full_termination(**) + super(**@opts, **) + end end end end diff --git a/lib/legion/extensions/extinction/helpers/archiver.rb b/lib/legion/extensions/extinction/helpers/archiver.rb index f8c1579..95b1d59 100644 --- a/lib/legion/extensions/extinction/helpers/archiver.rb +++ b/lib/legion/extensions/extinction/helpers/archiver.rb @@ -9,13 +9,12 @@ def initialize @archives = [] end - def archive(agent_id:, reason:, metadata: {}) - level = current_protocol_level + def archive(agent_id:, reason:, metadata: {}, current_level: 0) record = { agent_id: agent_id, reason: reason, metadata: metadata, - level: level, + level: current_level, archived_at: Time.now.utc.iso8601, state_snapshot: capture_state_snapshot } @@ -30,10 +29,6 @@ def all_archives private - def current_protocol_level - 0 - end - def capture_state_snapshot snapshot = {} snapshot[:mesh_connected] = true if defined?(Legion::Extensions::Mesh) diff --git a/lib/legion/extensions/extinction/helpers/protocol_state.rb b/lib/legion/extensions/extinction/helpers/protocol_state.rb index bb49735..ab03c01 100644 --- a/lib/legion/extensions/extinction/helpers/protocol_state.rb +++ b/lib/legion/extensions/extinction/helpers/protocol_state.rb @@ -9,7 +9,7 @@ module Helpers class ProtocolState MAX_HISTORY = 500 - attr_reader :history + attr_reader :current_level, :history def initialize @current_level = 0 diff --git a/lib/legion/extensions/extinction/runners/extinction.rb b/lib/legion/extensions/extinction/runners/extinction.rb index 3e01339..3f15354 100644 --- a/lib/legion/extensions/extinction/runners/extinction.rb +++ b/lib/legion/extensions/extinction/runners/extinction.rb @@ -64,7 +64,8 @@ def monitor_protocol(**) end def archive_agent(agent_id:, reason:, metadata: {}, **) - record = archiver.archive(agent_id: agent_id, reason: reason, metadata: metadata) + record = archiver.archive(agent_id: agent_id, reason: reason, metadata: metadata, + current_level: protocol_state.current_level) record_audit(action: :archive, details: { agent_id: agent_id, reason: reason }) { success: true, archive: record } end @@ -84,6 +85,12 @@ def full_termination(agent_id:, authority:, reason:, **) { success: true, agent_id: agent_id, archive: archive_result[:archive], terminated_at: Time.now.utc.iso8601 } end + # Reset internal state for test isolation + def reset! + @protocol_state = nil + @archiver = nil + end + private def protocol_state diff --git a/lib/legion/extensions/extinction/version.rb b/lib/legion/extensions/extinction/version.rb index ce987c5..a565a23 100644 --- a/lib/legion/extensions/extinction/version.rb +++ b/lib/legion/extensions/extinction/version.rb @@ -3,7 +3,7 @@ module Legion module Extensions module Extinction - VERSION = '0.2.11' + VERSION = '0.2.12' end end end From 1dfa1c718008cdbee7515d5d352b61555f6b42b8 Mon Sep 17 00:00:00 2001 From: Esity Date: Mon, 1 Jun 2026 14:11:24 -0500 Subject: [PATCH 2/2] bump version to 0.2.12, add changelog for structural fixes --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec624a5..e9289aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.2.12] - 2026-06-01 +### Fixed +- Archiver no longer hardcodes `current_protocol_level` to 0; runner passes actual protocol state level +- Client options (`@opts`) now merge into every runner call instead of being silently ignored +- Added `reset!` for test isolation; clarified `extend self` + `include` per-instance state behavior +- README `archive_on_escalate` default aligned with actual code default (`true`) + ## [0.2.11] - 2026-04-22 ### Fixed - ProtocolMonitor actor now delegates to runner instead of reimplementing a stub that always returned level 0