Skip to content

feat: event system improvements for navigation graph support#37

Merged
bkrabach merged 9 commits intomainfrom
feat/event-system-improvements
Mar 6, 2026
Merged

feat: event system improvements for navigation graph support#37
bkrabach merged 9 commits intomainfrom
feat/event-system-improvements

Conversation

@bkrabach
Copy link
Collaborator

@bkrabach bkrabach commented Mar 5, 2026

Multiple improvements to event system for navigation graph support:

  • Fixed session:end emission timing
  • Added session metadata passthrough on session:start and fork events
  • Updated orchestrator contract to mandate execution:start and execution:end events
  • Collapsed verbosity from 51 to 41 events (removed 10 tiered constants)

Context

Part of the Event System Improvements for Navigation Graph Support initiative.
Design doc: https://github.com/colombod/amplifier-event-and-data-model-for-context-intelligence

bkrabach added 9 commits March 5, 2026 02:23
The Python cleanup() method never emitted SESSION_END, while the Rust
implementation did. Now emits SESSION_END with session_id and status
before coordinator.cleanup(), guarded by self._initialized, wrapped
in try/except for best-effort reliability.
Add ordering test that records call sequence via hook handler and
tracking cleanup function, asserting SESSION_END fires first.
Addresses code quality review suggestion for explicit ordering
verification.
Read config.session.metadata and include it as optional 'metadata' key
in session:start, session:fork, and session:resume event payloads.

Pure passthrough — the kernel does not interpret, validate, or enforce
any schema on the metadata dict. The key is only included when
config.session.metadata is truthy, so existing consumers that do not
set metadata see no change in payload structure.

Tests added:
- test_session_start_includes_metadata_when_configured
- test_session_start_excludes_metadata_when_not_configured
- test_session_resume_includes_metadata_when_configured
- test_session_resume_excludes_metadata_when_not_configured
- test_session_fork_includes_metadata_when_configured
- test_session_fork_excludes_metadata_when_not_configured
- test_session_fork_still_has_parent_and_session_id
…rator contract

- Add coordinator parameter to Orchestrator.execute() protocol definition
  (optional; already passed by session.py in production — fixes contract drift)
- Add Required section for execution:start/end events with:
  - Payload specs: execution:start {prompt}, execution:end {response, status}
  - Status values: 'completed', 'cancelled', 'error'
  - Complete try/except/CancelledError code example covering all exit paths
  - Field reference table and note to use constants from amplifier_core.events
- Promote observability.events registration from Recommended to Required
  - Updated Observability section prose to MUST language
  - Added note that kernel-standard events need not be re-registered
- Update Validation Checklist:
  - Required: add execution:start/end check items (bolded)
  - Required: add observability.events registration item
  - Recommended: remove observability.events (now Required)
  - Required: update execute() signature to include coordinator=None
- Update frontmatter: last_modified date and protocol definition line range
CP-V Kernel verbosity collapse — Task 12 of 16.

BREAKING CHANGE: The 10 tiered :debug and :raw event constants are removed.
Hooks subscribed to session:start:debug, session:start:raw, session:fork:debug,
session:fork:raw, session:resume:debug, session:resume:raw, llm:request:debug,
llm:request:raw, llm:response:debug, llm:response:raw will no longer receive
events.

Changes:
- crates/amplifier-core/src/events.rs: Remove 10 :debug/:raw constants and
  their ALL_EVENTS entries; update tests (count 51→41, remove tiered entries)
- bindings/python/src/lib.rs: Remove 10 constant registrations from _engine
  module; update execute() to use emit_raw_field_if_configured instead of
  emit_debug_events (no tiers, single base event with optional raw field)
- python/amplifier_core/events.py: Remove 10 imports; build ALL_EVENTS list
  locally from 41 remaining constants (not from _engine to avoid stale .so)
- python/amplifier_core/session.py: Collapse initialize() fork path and
  execute() start/resume path from 3-tier to single emission; add raw field
  when session.raw=true; remove truncate_values import (no longer needed)
- python/amplifier_core/_session_exec.py: Replace emit_debug_events() with
  emit_raw_field_if_configured() — no tiered events, raw field only
- python/amplifier_core/_engine.pyi: Add 41 module-level event constant stubs;
  remove the 10 removed constants
- bindings/python/tests/test_event_constants.py: Update ALL_EVENT_NAMES (41),
  add REMOVED_EVENT_NAMES list for documentation; count 51→41
- bindings/python/tests/test_python_stubs.py: Update ALL_EVENTS count 51→41
- bindings/python/tests/test_schema_sync.py: Update ALL_EVENTS count 51→41
- tests/test_event_taxonomy.py: Remove :debug/:raw from valid_detail_suffixes;
  enforce that all events must be exactly 2-part namespace:action
- tests/test_cpv_kernel_verbosity_collapse.py: New test file with 22 tests
  verifying removed constants, count=41, raw field behavior, redaction

Config change: session.debug + session.raw_debug → single session.raw flag.
Set session.raw: true to include redacted config in event payloads.
Remove all archaeological CP-V references that made the codebase look
like tiered events were recently removed rather than never having existed.

Changes:
- Delete tests/test_cpv_kernel_verbosity_collapse.py (retcon violations:
  12 tests asserting removed events don't exist; raw field tests covered
  by test_session_metadata.py; count/suffix tests covered by
  test_event_taxonomy.py)
- python/amplifier_core/events.py: clean docstring, remove 'base events
  only — no :debug or :raw tiers' inline comments, strip defensive
  ALL_EVENTS comment about CP-V rebuild state
- python/amplifier_core/_engine.pyi: remove '41 canonical events
  (CP-V: 10 :debug/:raw tiers removed)' from event constants section
- tests/test_event_taxonomy.py: clean docstring and comments in
  test_events_follow_naming_convention
- bindings/python/tests/test_event_constants.py: remove CP-V header
  comment, delete unused REMOVED_EVENT_NAMES list, clean count message
- bindings/python/tests/test_python_stubs.py: remove CP-V inline comment
- bindings/python/tests/test_schema_sync.py: remove CP-V inline comment
- python/amplifier_core/_session_exec.py: clean docstring in
  emit_raw_field_if_configured
- bindings/python/src/lib.rs: remove CP-V comments from event constants
  section and is_resumed branch
- crates/amplifier-core/src/events.rs: remove CP-V sentence from
  ALL_EVENTS doc comment, clean test assertion message
…yi stubs

- events.py: add ALL_EVENTS to the _engine import block; delete the
  local 41-item list that duplicated the Rust-authoritative value
- _engine.pyi: remove the module-level event constant stubs block
  (~41 lines) that was added as defensive coding for a transitional
  state; restores the file to its origin/main shape
- tests: add test_all_events_from_engine.py which asserts that
  events.ALL_EVENTS is the exact object exported by _engine (not a
  locally-constructed copy)
@bkrabach bkrabach merged commit 5a74875 into main Mar 6, 2026
7 checks passed
bkrabach added a commit that referenced this pull request Mar 6, 2026
The verbosity collapse (PR #37) removed SESSION_FORK_DEBUG and
SESSION_FORK_RAW from events.py but missed the second fork emission
code path in _session_init.py (used by the Rust PyO3 bridge).

This caused every delegate/child session to crash at initialization:
  ImportError: cannot import name 'SESSION_FORK_DEBUG' from 'amplifier_core.events'

Fix: collapse _session_init.py to match the pattern already in session.py
- Remove SESSION_FORK_DEBUG, SESSION_FORK_RAW imports
- Remove truncate_values import (no longer needed)
- Remove debug/raw_debug config flag blocks
- Emit single SESSION_FORK with optional metadata and raw fields
  (reads session.metadata and session.raw, same as session.py)
bkrabach added a commit that referenced this pull request Mar 7, 2026
* feat: emit SESSION_END in Python cleanup() to match Rust behavior

The Python cleanup() method never emitted SESSION_END, while the Rust
implementation did. Now emits SESSION_END with session_id and status
before coordinator.cleanup(), guarded by self._initialized, wrapped
in try/except for best-effort reliability.

* fix: log SESSION_END emission failure in cleanup instead of silently passing

* test: verify SESSION_END emits before coordinator.cleanup()

Add ordering test that records call sequence via hook handler and
tracking cleanup function, asserting SESSION_END fires first.
Addresses code quality review suggestion for explicit ordering
verification.

* feat: CP-SM — session metadata passthrough on session:start/fork/resume

Read config.session.metadata and include it as optional 'metadata' key
in session:start, session:fork, and session:resume event payloads.

Pure passthrough — the kernel does not interpret, validate, or enforce
any schema on the metadata dict. The key is only included when
config.session.metadata is truthy, so existing consumers that do not
set metadata see no change in payload structure.

Tests added:
- test_session_start_includes_metadata_when_configured
- test_session_start_excludes_metadata_when_not_configured
- test_session_resume_includes_metadata_when_configured
- test_session_resume_excludes_metadata_when_not_configured
- test_session_fork_includes_metadata_when_configured
- test_session_fork_excludes_metadata_when_not_configured
- test_session_fork_still_has_parent_and_session_id

* docs: mandate execution:start/end and observability.events in orchestrator contract

- Add coordinator parameter to Orchestrator.execute() protocol definition
  (optional; already passed by session.py in production — fixes contract drift)
- Add Required section for execution:start/end events with:
  - Payload specs: execution:start {prompt}, execution:end {response, status}
  - Status values: 'completed', 'cancelled', 'error'
  - Complete try/except/CancelledError code example covering all exit paths
  - Field reference table and note to use constants from amplifier_core.events
- Promote observability.events registration from Recommended to Required
  - Updated Observability section prose to MUST language
  - Added note that kernel-standard events need not be re-registered
- Update Validation Checklist:
  - Required: add execution:start/end check items (bolded)
  - Required: add observability.events registration item
  - Recommended: remove observability.events (now Required)
  - Required: update execute() signature to include coordinator=None
- Update frontmatter: last_modified date and protocol definition line range

* feat(cp-v): remove tiered event constants, collapse session.py emissions

CP-V Kernel verbosity collapse — Task 12 of 16.

BREAKING CHANGE: The 10 tiered :debug and :raw event constants are removed.
Hooks subscribed to session:start:debug, session:start:raw, session:fork:debug,
session:fork:raw, session:resume:debug, session:resume:raw, llm:request:debug,
llm:request:raw, llm:response:debug, llm:response:raw will no longer receive
events.

Changes:
- crates/amplifier-core/src/events.rs: Remove 10 :debug/:raw constants and
  their ALL_EVENTS entries; update tests (count 51→41, remove tiered entries)
- bindings/python/src/lib.rs: Remove 10 constant registrations from _engine
  module; update execute() to use emit_raw_field_if_configured instead of
  emit_debug_events (no tiers, single base event with optional raw field)
- python/amplifier_core/events.py: Remove 10 imports; build ALL_EVENTS list
  locally from 41 remaining constants (not from _engine to avoid stale .so)
- python/amplifier_core/session.py: Collapse initialize() fork path and
  execute() start/resume path from 3-tier to single emission; add raw field
  when session.raw=true; remove truncate_values import (no longer needed)
- python/amplifier_core/_session_exec.py: Replace emit_debug_events() with
  emit_raw_field_if_configured() — no tiered events, raw field only
- python/amplifier_core/_engine.pyi: Add 41 module-level event constant stubs;
  remove the 10 removed constants
- bindings/python/tests/test_event_constants.py: Update ALL_EVENT_NAMES (41),
  add REMOVED_EVENT_NAMES list for documentation; count 51→41
- bindings/python/tests/test_python_stubs.py: Update ALL_EVENTS count 51→41
- bindings/python/tests/test_schema_sync.py: Update ALL_EVENTS count 51→41
- tests/test_event_taxonomy.py: Remove :debug/:raw from valid_detail_suffixes;
  enforce that all events must be exactly 2-part namespace:action
- tests/test_cpv_kernel_verbosity_collapse.py: New test file with 22 tests
  verifying removed constants, count=41, raw field behavior, redaction

Config change: session.debug + session.raw_debug → single session.raw flag.
Set session.raw: true to include redacted config in event payloads.

* refactor: clean up retcon references from verbosity collapse

Remove all archaeological CP-V references that made the codebase look
like tiered events were recently removed rather than never having existed.

Changes:
- Delete tests/test_cpv_kernel_verbosity_collapse.py (retcon violations:
  12 tests asserting removed events don't exist; raw field tests covered
  by test_session_metadata.py; count/suffix tests covered by
  test_event_taxonomy.py)
- python/amplifier_core/events.py: clean docstring, remove 'base events
  only — no :debug or :raw tiers' inline comments, strip defensive
  ALL_EVENTS comment about CP-V rebuild state
- python/amplifier_core/_engine.pyi: remove '41 canonical events
  (CP-V: 10 :debug/:raw tiers removed)' from event constants section
- tests/test_event_taxonomy.py: clean docstring and comments in
  test_events_follow_naming_convention
- bindings/python/tests/test_event_constants.py: remove CP-V header
  comment, delete unused REMOVED_EVENT_NAMES list, clean count message
- bindings/python/tests/test_python_stubs.py: remove CP-V inline comment
- bindings/python/tests/test_schema_sync.py: remove CP-V inline comment
- python/amplifier_core/_session_exec.py: clean docstring in
  emit_raw_field_if_configured
- bindings/python/src/lib.rs: remove CP-V comments from event constants
  section and is_resumed branch
- crates/amplifier-core/src/events.rs: remove CP-V sentence from
  ALL_EVENTS doc comment, clean test assertion message

* fix: resolve CI failures — cargo fmt and rename emit_debug_events reference

* refactor: remove duplicated ALL_EVENTS list and unnecessary _engine.pyi stubs

- events.py: add ALL_EVENTS to the _engine import block; delete the
  local 41-item list that duplicated the Rust-authoritative value
- _engine.pyi: remove the module-level event constant stubs block
  (~41 lines) that was added as defensive coding for a transitional
  state; restores the file to its origin/main shape
- tests: add test_all_events_from_engine.py which asserts that
  events.ALL_EVENTS is the exact object exported by _engine (not a
  locally-constructed copy)
bkrabach added a commit that referenced this pull request Mar 7, 2026
The verbosity collapse (PR #37) removed SESSION_FORK_DEBUG and
SESSION_FORK_RAW from events.py but missed the second fork emission
code path in _session_init.py (used by the Rust PyO3 bridge).

This caused every delegate/child session to crash at initialization:
  ImportError: cannot import name 'SESSION_FORK_DEBUG' from 'amplifier_core.events'

Fix: collapse _session_init.py to match the pattern already in session.py
- Remove SESSION_FORK_DEBUG, SESSION_FORK_RAW imports
- Remove truncate_values import (no longer needed)
- Remove debug/raw_debug config flag blocks
- Emit single SESSION_FORK with optional metadata and raw fields
  (reads session.metadata and session.raw, same as session.py)
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