Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d8dd32d
feat(OMN-2117): Canonical state nodes — session state effect + lifecy…
jonahgabriel Feb 11, 2026
357bbe4
fix(review): [critical+major+minor] Path traversal, async safety, and…
jonahgabriel Feb 11, 2026
505651b
fix(review): [minor] Remove unused imports, add path traversal tests
jonahgabriel Feb 11, 2026
d16aa9b
fix(review): [major+minor] FD leak, unbounded runs, FSM enforcement, …
jonahgabriel Feb 11, 2026
77484a3
fix(review): [major+minor] Path traversal guard in write handler, GC …
jonahgabriel Feb 11, 2026
e47babd
fix(review): [major+minor] Bounded GC, serialization round-trip, run_…
jonahgabriel Feb 11, 2026
ed7f553
fix(review): [major+minor] FD leak on fdopen failure, TOCTOU resolve,…
jonahgabriel Feb 11, 2026
bb7558b
fix(review): [minor] Use >= for TTL boundary in is_stale() to avoid e…
jonahgabriel Feb 11, 2026
713b09e
fix(review): [major+minor] Resolve-path guard on write, broad excepti…
jonahgabriel Feb 11, 2026
7d46c56
fix(review): [major+minor] Metadata type safety, error logging, run_i…
jonahgabriel Feb 11, 2026
2d35533
fix(review): [major+minor] active_run_id validation, GC missing_ok, G…
jonahgabriel Feb 11, 2026
edef3a3
fix(review): [major+minor] Atomic RMW, trim-active guard, shared run_…
jonahgabriel Feb 11, 2026
f328999
fix(review): [major+minor] Union threshold test, GC delete-after-trac…
jonahgabriel Feb 11, 2026
a09c2e4
fix(review): [minor] GC malformed append-before-unlink, RMW TOCTOU fix
jonahgabriel Feb 11, 2026
328d0e2
fix(review): [major+minor] Reducer run_id validation, RMW self-heal, …
jonahgabriel Feb 11, 2026
64d83cd
fix(review): [major+minor] GC file counting, shallow copy docs, resol…
jonahgabriel Feb 11, 2026
6946fd1
fix(review): [minor] GC race condition — skip concurrent deletions in…
jonahgabriel Feb 11, 2026
c3ed5af
fix(review): [minor] Clarify resolve() comment and document clock-ske…
jonahgabriel Feb 11, 2026
badf0e0
fix(review): [minor] ValidationError catch, GC docs, crash-resilient …
jonahgabriel Feb 11, 2026
71563f5
fix(review): [minor] Unconditional defensive copy, files_affected con…
jonahgabriel Feb 11, 2026
b08b075
fix(review): [major+minor+nitpick] Handler properties, error sanitiza…
jonahgabriel Feb 11, 2026
6137b5c
fix(review): [major+minor+nitpick] Handler properties, error sanitiza…
jonahgabriel Feb 11, 2026
48a05e8
merge: resolve conflicts with main (keep both OMN-2117 + OMN-2125 add…
jonahgabriel Feb 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/omnibase_infra/enums/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@
from omnibase_infra.enums.enum_retry_error_category import EnumRetryErrorCategory
from omnibase_infra.enums.enum_security_rule_id import EnumSecurityRuleId
from omnibase_infra.enums.enum_selection_strategy import EnumSelectionStrategy
from omnibase_infra.enums.enum_session_lifecycle_state import (
EnumSessionLifecycleState,
)
from omnibase_infra.enums.enum_topic_standard import EnumTopicStandard
from omnibase_infra.enums.enum_validation_severity import EnumValidationSeverity

Expand Down Expand Up @@ -149,6 +152,7 @@
"EnumRetryErrorCategory",
"EnumSecurityRuleId",
"EnumSelectionStrategy",
"EnumSessionLifecycleState",
"EnumTopicStandard",
"EnumTopicType",
"EnumValidationSeverity",
Expand Down
38 changes: 38 additions & 0 deletions src/omnibase_infra/enums/enum_session_lifecycle_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 OmniNode Team
"""Session lifecycle FSM states.

Defines the state machine states for session lifecycle management.
Used by the session lifecycle reducer for concurrent pipeline isolation.

FSM Diagram::

+------+ create_run +-------------+ activate_run +------------+
| idle | -------------> | run_created | ---------------> | run_active |
+------+ +-------------+ +------------+
^ |
| +----------+ |
+--------------------| run_ended | <-----------------------+
+----------+ end_run
"""

from enum import Enum


class EnumSessionLifecycleState(str, Enum):
"""Session lifecycle FSM states.

Attributes:
IDLE: No active run — waiting for a pipeline to start.
RUN_CREATED: Run document created, not yet active.
RUN_ACTIVE: Run is actively executing.
RUN_ENDED: Run has completed or been terminated.
"""

IDLE = "idle"
RUN_CREATED = "run_created"
RUN_ACTIVE = "run_active"
RUN_ENDED = "run_ended"


__all__: list[str] = ["EnumSessionLifecycleState"]
20 changes: 20 additions & 0 deletions src/omnibase_infra/nodes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,39 @@
NodeRegistrationReducer,
RegistryInfraNodeRegistrationReducer,
)
from omnibase_infra.nodes.node_session_lifecycle_reducer import (
ModelSessionLifecycleState,
NodeSessionLifecycleReducer,
RegistryInfraSessionLifecycle,
)
from omnibase_infra.nodes.node_session_state_effect import (
ModelRunContext,
ModelSessionIndex,
ModelSessionStateResult,
NodeSessionStateEffect,
RegistryInfraSessionState,
)
from omnibase_infra.nodes.reducers import RegistrationReducer

__all__: list[str] = [
"ModelBackendResult",
"ModelRegistryRequest",
"ModelRegistryResponse",
"ModelRunContext",
"ModelSessionIndex",
"ModelSessionLifecycleState",
"ModelSessionStateResult",
"NodeAuthGateCompute",
"NodeLedgerProjectionCompute",
"NodeRegistrationOrchestrator",
"NodeRegistrationReducer",
"NodeRegistryEffect",
"NodeSessionLifecycleReducer",
"NodeSessionStateEffect",
"RegistrationReducer",
"RegistryInfraAuthGateCompute",
"RegistryInfraLedgerProjection",
"RegistryInfraNodeRegistrationReducer",
"RegistryInfraSessionLifecycle",
"RegistryInfraSessionState",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 OmniNode Team
"""Node Session Lifecycle Reducer — pure FSM for session lifecycle.

This package provides the NodeSessionLifecycleReducer, a pure FSM reducer
that tracks the lifecycle of pipeline runs: idle -> run_created -> run_active
-> run_ended -> idle.

Available Exports:
- NodeSessionLifecycleReducer: The declarative reducer node
- ModelSessionLifecycleState: Immutable FSM state model
- RegistryInfraSessionLifecycle: DI registry

Tracking:
- OMN-2117: Canonical State Nodes
"""

from omnibase_infra.nodes.node_session_lifecycle_reducer.models import (
ModelSessionLifecycleState,
)
from omnibase_infra.nodes.node_session_lifecycle_reducer.node import (
NodeSessionLifecycleReducer,
)
from omnibase_infra.nodes.node_session_lifecycle_reducer.registry import (
RegistryInfraSessionLifecycle,
)

__all__: list[str] = [
"ModelSessionLifecycleState",
"NodeSessionLifecycleReducer",
"RegistryInfraSessionLifecycle",
]
181 changes: 181 additions & 0 deletions src/omnibase_infra/nodes/node_session_lifecycle_reducer/contract.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 OmniNode Team
# ONEX Node Contract — Session Lifecycle Reducer
#
# Pure FSM for session lifecycle management.
# Tracks: idle -> run_created -> run_active -> run_ended -> idle
#
# Concurrency rules:
# - Each pipeline creates its own runs/{run_id}.json
# - session.json updates are append-only for recent_run_ids
# - active_run_id is advisory (for interactive sessions)
# - Multiple active runs allowed; destructive ops denied
# until /onex:set-active-run {run_id} disambiguates
#
# Related Tickets:
# - OMN-2117: Canonical State Nodes
# - OMN-2005: Workflow Automation (parent)
# =============================================================================
# Contract identifiers
name: "node_session_lifecycle_reducer"
contract_name: "node_session_lifecycle_reducer"
node_name: "node_session_lifecycle_reducer"
contract_version:
major: 0
minor: 1
patch: 0
node_version:
major: 0
minor: 1
patch: 0
# Node type
node_type: "REDUCER_GENERIC"
# Description
description: >
Pure reducer for session lifecycle management. Tracks the FSM idle -> run_created -> run_active -> run_ended for each pipeline run. Emits intents for session index and run context writes. Supports concurrent pipeline isolation via per-run FSM instances.

# I/O Models
input_model:
name: "ModelReducerInput"
module: "omnibase_core.models.reducer.model_reducer_input"
description: "Reducer input containing session event and trigger."
output_model:
name: "ModelReducerOutput"
module: "omnibase_core.models.reducer.model_reducer_output"
description: "Reducer output containing new state and session intents."
# FSM State Machine Definition
# ============================
#
# State Diagram:
# +------+ create_run +-------------+ activate_run +------------+
# | idle | -------------> | run_created | ---------------> | run_active |
# +------+ +-------------+ +------------+
# ^ |
# | +----------+ |
# +--------------------| run_ended | <-----------------------+
# reset +----------+ end_run
#
state_machine:
state_machine_name: "session_lifecycle_fsm"
initial_state: "idle"
states:
- state_name: "idle"
description: "No active run — waiting for pipeline start"
entry_actions: []
exit_actions: []
required_data: []
- state_name: "run_created"
description: "Run document created, not yet active"
entry_actions:
- "emit_run_context_write_intent"
- "emit_session_index_update_intent"
exit_actions: []
required_data:
- "run_id"
- state_name: "run_active"
description: "Run is actively executing"
entry_actions:
- "emit_run_context_update_intent"
exit_actions: []
required_data:
- "run_id"
- state_name: "run_ended"
description: "Run has completed or been terminated"
entry_actions:
- "emit_run_context_update_intent"
- "emit_session_index_cleanup_intent"
exit_actions: []
required_data:
- "run_id"
transitions:
# idle -> run_created: On pipeline start
- from_state: "idle"
to_state: "run_created"
trigger: "create_run"
description: "Create a new pipeline run"
conditions:
- expression: "run_id is_present"
required: true
actions:
- action_name: "build_run_context_write_intent"
action_type: "intent_emission"
- action_name: "build_session_index_add_run_intent"
action_type: "intent_emission"
# run_created -> run_active: On run activation
- from_state: "run_created"
to_state: "run_active"
trigger: "activate_run"
description: "Activate the run (start executing)"
actions:
- action_name: "build_run_context_activate_intent"
action_type: "intent_emission"
# run_active -> run_ended: On run completion
- from_state: "run_active"
to_state: "run_ended"
trigger: "end_run"
description: "End the current run"
actions:
- action_name: "build_run_context_end_intent"
action_type: "intent_emission"
# run_ended -> idle: Reset for next run
- from_state: "run_ended"
to_state: "idle"
trigger: "reset"
description: "Reset to idle for next pipeline run"
actions:
- action_name: "clear_run_state"
action_type: "state_update"
persistence_enabled: true
terminal_states: []
# run_ended is NOT a true terminal — it resets to idle
# Intent Emission Configuration
# ============================
intent_emission:
enabled: true
intents:
- intent_type: "session.index.write"
target_pattern: "filesystem://state/session.json"
payload_model: "ModelSessionIndex"
payload_module: "omnibase_infra.nodes.node_session_state_effect.models"
description: "Write updated session index with new run"
- intent_type: "session.run.write"
target_pattern: "filesystem://state/runs/{run_id}.json"
payload_model: "ModelRunContext"
payload_module: "omnibase_infra.nodes.node_session_state_effect.models"
description: "Write run context document"
# State Model Configuration
state_model:
name: "ModelSessionLifecycleState"
module: "omnibase_infra.nodes.node_session_lifecycle_reducer.models"
description: "Immutable state model for session lifecycle FSM"
# Idempotency Configuration
idempotency:
enabled: true
strategy: "event_id_tracking"
description: "Skip duplicate events based on last_processed_event_id"
# Dependencies
dependencies:
- name: "container"
type: "ModelONEXContainer"
module: "omnibase_core.models.container.model_onex_container"
description: "ONEX dependency injection container"
# Health check
health_check:
enabled: true
endpoint: "/health"
interval_seconds: 30
# Metadata
metadata:
author: "OmniNode Team"
license: "MIT"
created: "2026-02-10"
tags:
- reducer
- session
- lifecycle
- fsm
- pure-function
- concurrent-pipeline
related_tickets:
- "OMN-2117"
- "OMN-2005"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 OmniNode Team
"""Models for the session lifecycle reducer node."""

from omnibase_infra.nodes.node_session_lifecycle_reducer.models.model_session_lifecycle_state import (
ModelSessionLifecycleState,
)

__all__: list[str] = ["ModelSessionLifecycleState"]
Loading