diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4d2f3056..b4e0daa1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,36 @@ jobs: uv run ruff check tooling/ uv run ruff format --check tooling/ - # Job 2b: Lint GitHub Actions workflows + # Job 2b: Lint Protobuf files + lint-proto: + name: Lint Protobuf + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Need full history for breaking change detection + + - name: Install buf + uses: bufbuild/buf-setup-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Lint protobuf files + run: cd proto && buf lint + + - name: Check protobuf formatting + run: cd proto && buf format --diff --exit-code + + - name: Check for breaking changes + if: github.event_name == 'pull_request' + run: | + cd proto + buf breaking --against "../.git#branch=origin/main,subdir=proto" + + # Job 2c: Lint GitHub Actions workflows lint-github-actions: name: Lint GitHub Actions runs-on: ubuntu-latest @@ -445,7 +474,7 @@ jobs: name: Build All Components runs-on: ubuntu-latest timeout-minutes: 20 - needs: [generate-proto, lint-rust, lint-python, lint-github-actions, lint-go, test-proxy, test-patterns, test-integration] + needs: [generate-proto, lint-rust, lint-python, lint-proto, lint-github-actions, lint-go, test-proxy, test-patterns, test-integration] steps: - name: Checkout @@ -573,7 +602,7 @@ jobs: name: CI Status Check runs-on: ubuntu-latest timeout-minutes: 5 - needs: [lint-rust, lint-python, lint-github-actions, lint-go, test-proxy, test-patterns, test-integration, validate-docs, build] + needs: [lint-rust, lint-python, lint-proto, lint-github-actions, lint-go, test-proxy, test-patterns, test-integration, validate-docs, build] if: always() steps: @@ -582,6 +611,7 @@ jobs: run: | if [[ "${{ needs.lint-rust.result }}" != "success" ]] || \ [[ "${{ needs.lint-python.result }}" != "success" ]] || \ + [[ "${{ needs.lint-proto.result }}" != "success" ]] || \ [[ "${{ needs.lint-github-actions.result }}" != "success" ]] || \ [[ "${{ needs.lint-go.result }}" != "success" ]] || \ [[ "${{ needs.test-proxy.result }}" != "success" ]] || \ @@ -608,6 +638,7 @@ jobs: # Build job results summary JOBS="Lint Rust: ${{ needs.lint-rust.result == 'success' && '✅' || '❌' }} Lint Python: ${{ needs.lint-python.result == 'success' && '✅' || '❌' }} + Lint Protobuf: ${{ needs.lint-proto.result == 'success' && '✅' || '❌' }} Lint GitHub Actions: ${{ needs.lint-github-actions.result == 'success' && '✅' || '❌' }} Lint Go: ${{ needs.lint-go.result == 'success' && '✅' || '❌' }} Test Proxy: ${{ needs.test-proxy.result == 'success' && '✅' || '❌' }} diff --git a/Makefile b/Makefile index 9ae678384..41530ee7d 100644 --- a/Makefile +++ b/Makefile @@ -449,7 +449,7 @@ watch-proxy: ## Watch and rebuild proxy on changes (requires cargo-watch) watch-test: ## Watch and rerun tests on changes (requires cargo-watch) @cd prism-proxy && cargo watch -x test -fmt: fmt-rust fmt-go fmt-python ## Format all code +fmt: fmt-rust fmt-go fmt-python fmt-proto ## Format all code fmt-rust: ## Format Rust code $(call print_blue,Formatting Rust code...) @@ -476,7 +476,13 @@ fmt-python: ## Format Python code with ruff @uv run ruff format tooling/ $(call print_green,Python code formatted) -lint: lint-rust lint-go lint-python lint-workflows ## Lint all code and workflows +fmt-proto: ## Format protobuf files with buf + $(call print_blue,Formatting protobuf files...) + @command -v buf >/dev/null 2>&1 || { echo "⚠️ buf not installed. Install with: brew install bufbuild/buf/buf"; exit 1; } + @cd proto && buf format -w + $(call print_green,Protobuf files formatted) + +lint: lint-rust lint-go lint-python lint-proto lint-workflows ## Lint all code, proto, and workflows lint-rust: ## Lint Rust code with clippy $(call print_blue,Linting Rust code...) @@ -524,6 +530,30 @@ lint-parallel-critical: lint-rust lint-python ## Lint critical categories only i lint-parallel-list: ## List all available linter categories @uv run tooling/parallel_lint.py --list +lint-proto: lint-proto-buf lint-proto-breaking ## Lint protobuf files and check for breaking changes + +lint-proto-buf: ## Lint protobuf files with buf + $(call print_blue,Linting protobuf files with buf...) + @command -v buf >/dev/null 2>&1 || { echo "⚠️ buf not installed. Install with: brew install bufbuild/buf/buf"; exit 1; } + @cd proto && buf lint + $(call print_green,Protobuf linting complete) + +lint-proto-breaking: ## Check for breaking changes in protobuf files against main branch + $(call print_blue,Checking for protobuf breaking changes...) + @command -v buf >/dev/null 2>&1 || { echo "⚠️ buf not installed. Install with: brew install bufbuild/buf/buf"; exit 1; } + @if git rev-parse --verify origin/main >/dev/null 2>&1; then \ + cd proto && buf breaking --against "../.git#branch=origin/main,subdir=proto" && \ + printf "$(GREEN)✓ No breaking changes detected$(NC)\n"; \ + else \ + printf "$(YELLOW)⚠️ Cannot check breaking changes: origin/main not found$(NC)\n"; \ + fi + +lint-proto-format: ## Check protobuf file formatting with buf + $(call print_blue,Checking protobuf file formatting...) + @command -v buf >/dev/null 2>&1 || { echo "⚠️ buf not installed. Install with: brew install bufbuild/buf/buf"; exit 1; } + @cd proto && buf format --diff --exit-code + $(call print_green,Protobuf formatting check complete) + lint-workflows: ## Lint GitHub Actions workflows with actionlint $(call print_blue,Linting GitHub Actions workflows...) @command -v actionlint >/dev/null 2>&1 || { echo "⚠️ actionlint not installed. Install with: brew install actionlint"; exit 1; } @@ -537,6 +567,7 @@ lint-fix: ## Auto-fix linting issues where possible @cd prism-proxy && cargo clippy --fix --allow-dirty -- -D warnings @uv run ruff check --fix tooling/ @uv run ruff format tooling/ + @command -v buf >/dev/null 2>&1 && cd proto && buf format -w || echo "⚠️ buf not installed, skipping proto format" $(call print_green,Auto-fix complete) ##@ Podman & Compose diff --git a/proto/buf.yaml b/proto/buf.yaml index 2dbb37cd7..039a6dea1 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -13,6 +13,8 @@ lint: - ENUM_VALUE_PREFIX - RPC_REQUEST_STANDARD_NAME - RPC_RESPONSE_STANDARD_NAME + # Allow reusing common response types like HeartbeatAck across multiple RPCs + - RPC_REQUEST_RESPONSE_UNIQUE # Allow unversioned packages for options and common types - PACKAGE_VERSION_SUFFIX # Allow "Interface" suffix for backend interface services (Layer 1) @@ -25,8 +27,14 @@ breaking: use: - FILE except: - # Allow adding fields (backward compatible) - - FIELD_SAME_LABEL + # Allow adding fields (backward compatible) - using new rules + - FIELD_SAME_CARDINALITY + - FIELD_WIRE_COMPATIBLE_CARDINALITY + - FIELD_WIRE_JSON_COMPATIBLE_CARDINALITY + # Allow enum value name changes (for UNSPECIFIED zero value migration) + - ENUM_VALUE_SAME_NAME + # Allow file deletions (control_plane.proto was already removed) + - FILE_NO_DELETE # Code generation inputs build: diff --git a/proto/prism/common/errors.proto b/proto/prism/common/errors.proto index 30ed3e904..cd393170d 100644 --- a/proto/prism/common/errors.proto +++ b/proto/prism/common/errors.proto @@ -2,11 +2,11 @@ syntax = "proto3"; package prism.common; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/common"; - import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/common"; + // Error represents a structured error response with rich context for distributed systems. // // Design Philosophy: @@ -58,7 +58,7 @@ message Error { map metadata = 13; // Stack trace (for debugging, should be filtered in production responses) - optional string stack_trace = 14 [deprecated = true]; // Use debug_info instead + optional string stack_trace = 14 [deprecated = true]; // Use debug_info instead // Debug information (only populated in debug mode) optional DebugInfo debug_info = 15; @@ -72,57 +72,57 @@ enum ErrorCode { ERROR_CODE_OK = 200; // 4xx Client Errors (caller should fix) - ERROR_CODE_BAD_REQUEST = 400; // Invalid request syntax/parameters - ERROR_CODE_UNAUTHORIZED = 401; // Authentication required - ERROR_CODE_FORBIDDEN = 403; // Authenticated but not authorized - ERROR_CODE_NOT_FOUND = 404; // Resource doesn't exist - ERROR_CODE_METHOD_NOT_ALLOWED = 405; // Operation not supported - ERROR_CODE_CONFLICT = 409; // Resource state conflict - ERROR_CODE_GONE = 410; // Resource permanently deleted - ERROR_CODE_PRECONDITION_FAILED = 412; // Precondition not met (e.g., CAS) - ERROR_CODE_PAYLOAD_TOO_LARGE = 413; // Request exceeds size limits - ERROR_CODE_UNPROCESSABLE_ENTITY = 422; // Validation failed - ERROR_CODE_TOO_MANY_REQUESTS = 429; // Rate limit exceeded + ERROR_CODE_BAD_REQUEST = 400; // Invalid request syntax/parameters + ERROR_CODE_UNAUTHORIZED = 401; // Authentication required + ERROR_CODE_FORBIDDEN = 403; // Authenticated but not authorized + ERROR_CODE_NOT_FOUND = 404; // Resource doesn't exist + ERROR_CODE_METHOD_NOT_ALLOWED = 405; // Operation not supported + ERROR_CODE_CONFLICT = 409; // Resource state conflict + ERROR_CODE_GONE = 410; // Resource permanently deleted + ERROR_CODE_PRECONDITION_FAILED = 412; // Precondition not met (e.g., CAS) + ERROR_CODE_PAYLOAD_TOO_LARGE = 413; // Request exceeds size limits + ERROR_CODE_UNPROCESSABLE_ENTITY = 422; // Validation failed + ERROR_CODE_TOO_MANY_REQUESTS = 429; // Rate limit exceeded // 5xx Server Errors (caller should retry) - ERROR_CODE_INTERNAL_ERROR = 500; // Unexpected internal error - ERROR_CODE_NOT_IMPLEMENTED = 501; // Feature not implemented - ERROR_CODE_BAD_GATEWAY = 502; // Upstream backend error - ERROR_CODE_SERVICE_UNAVAILABLE = 503; // Temporarily unavailable - ERROR_CODE_GATEWAY_TIMEOUT = 504; // Upstream timeout - ERROR_CODE_INSUFFICIENT_STORAGE = 507; // Backend storage full + ERROR_CODE_INTERNAL_ERROR = 500; // Unexpected internal error + ERROR_CODE_NOT_IMPLEMENTED = 501; // Feature not implemented + ERROR_CODE_BAD_GATEWAY = 502; // Upstream backend error + ERROR_CODE_SERVICE_UNAVAILABLE = 503; // Temporarily unavailable + ERROR_CODE_GATEWAY_TIMEOUT = 504; // Upstream timeout + ERROR_CODE_INSUFFICIENT_STORAGE = 507; // Backend storage full // Custom Prism Errors (600+) - ERROR_CODE_BACKEND_ERROR = 600; // Backend-specific error - ERROR_CODE_PATTERN_ERROR = 601; // Pattern-level semantic error + ERROR_CODE_BACKEND_ERROR = 600; // Backend-specific error + ERROR_CODE_PATTERN_ERROR = 601; // Pattern-level semantic error ERROR_CODE_INTERFACE_NOT_SUPPORTED = 602; // Backend doesn't implement interface - ERROR_CODE_SLOT_ERROR = 603; // Pattern slot configuration error - ERROR_CODE_CIRCUIT_BREAKER_OPEN = 604; // Circuit breaker preventing requests + ERROR_CODE_SLOT_ERROR = 603; // Pattern slot configuration error + ERROR_CODE_CIRCUIT_BREAKER_OPEN = 604; // Circuit breaker preventing requests } // ErrorCategory classifies errors for metrics, alerting, and handling enum ErrorCategory { ERROR_CATEGORY_UNSPECIFIED = 0; - ERROR_CATEGORY_CLIENT_ERROR = 1; // User/application error - ERROR_CATEGORY_SERVER_ERROR = 2; // Internal service error - ERROR_CATEGORY_BACKEND_ERROR = 3; // Backend storage error - ERROR_CATEGORY_NETWORK_ERROR = 4; // Network connectivity issue - ERROR_CATEGORY_TIMEOUT_ERROR = 5; // Operation timed out - ERROR_CATEGORY_RATE_LIMIT_ERROR = 6; // Quota/rate limit exceeded + ERROR_CATEGORY_CLIENT_ERROR = 1; // User/application error + ERROR_CATEGORY_SERVER_ERROR = 2; // Internal service error + ERROR_CATEGORY_BACKEND_ERROR = 3; // Backend storage error + ERROR_CATEGORY_NETWORK_ERROR = 4; // Network connectivity issue + ERROR_CATEGORY_TIMEOUT_ERROR = 5; // Operation timed out + ERROR_CATEGORY_RATE_LIMIT_ERROR = 6; // Quota/rate limit exceeded ERROR_CATEGORY_AUTHORIZATION_ERROR = 7; // Permission denied - ERROR_CATEGORY_VALIDATION_ERROR = 8; // Input validation failed - ERROR_CATEGORY_RESOURCE_ERROR = 9; // Resource not found/unavailable - ERROR_CATEGORY_CONCURRENCY_ERROR = 10; // Concurrent modification conflict + ERROR_CATEGORY_VALIDATION_ERROR = 8; // Input validation failed + ERROR_CATEGORY_RESOURCE_ERROR = 9; // Resource not found/unavailable + ERROR_CATEGORY_CONCURRENCY_ERROR = 10; // Concurrent modification conflict } // ErrorSeverity indicates impact level for prioritization enum ErrorSeverity { ERROR_SEVERITY_UNSPECIFIED = 0; - ERROR_SEVERITY_DEBUG = 1; // Informational, no action needed - ERROR_SEVERITY_INFO = 2; // Notable but expected (e.g., cache miss) - ERROR_SEVERITY_WARNING = 3; // Degraded but functional - ERROR_SEVERITY_ERROR = 4; // Operation failed, action may be needed - ERROR_SEVERITY_CRITICAL = 5; // Severe failure, immediate action required + ERROR_SEVERITY_DEBUG = 1; // Informational, no action needed + ERROR_SEVERITY_INFO = 2; // Notable but expected (e.g., cache miss) + ERROR_SEVERITY_WARNING = 3; // Degraded but functional + ERROR_SEVERITY_ERROR = 4; // Operation failed, action may be needed + ERROR_SEVERITY_CRITICAL = 5; // Severe failure, immediate action required } // RetryPolicy provides guidance on how/when to retry @@ -149,11 +149,11 @@ message RetryPolicy { // BackoffStrategy for retry timing enum BackoffStrategy { BACKOFF_STRATEGY_UNSPECIFIED = 0; - BACKOFF_STRATEGY_IMMEDIATE = 1; // Retry immediately - BACKOFF_STRATEGY_LINEAR = 2; // Linear backoff (delay * attempt) - BACKOFF_STRATEGY_EXPONENTIAL = 3; // Exponential backoff (delay * multiplier^attempt) - BACKOFF_STRATEGY_JITTER = 4; // Exponential with random jitter - BACKOFF_STRATEGY_NEVER = 5; // Don't retry (permanent failure) + BACKOFF_STRATEGY_IMMEDIATE = 1; // Retry immediately + BACKOFF_STRATEGY_LINEAR = 2; // Linear backoff (delay * attempt) + BACKOFF_STRATEGY_EXPONENTIAL = 3; // Exponential backoff (delay * multiplier^attempt) + BACKOFF_STRATEGY_JITTER = 4; // Exponential with random jitter + BACKOFF_STRATEGY_NEVER = 5; // Don't retry (permanent failure) } // ErrorDetail provides structured error information diff --git a/proto/prism/common/metadata.proto b/proto/prism/common/metadata.proto index 30acc08eb..ad4bf3135 100644 --- a/proto/prism/common/metadata.proto +++ b/proto/prism/common/metadata.proto @@ -2,10 +2,10 @@ syntax = "proto3"; package prism.common; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/common"; - import "prism/common/types.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/common"; + // Metadata for stored items message ItemMetadata { // Compression info @@ -26,13 +26,13 @@ message ItemMetadata { } message EncryptionInfo { - string algorithm = 1; // e.g., "AES-256-GCM" - string key_id = 2; // Key version for rotation + string algorithm = 1; // e.g., "AES-256-GCM" + string key_id = 2; // Key version for rotation } message ChunkMetadata { int32 total_chunks = 1; int32 chunk_size_bytes = 2; - string hash_algorithm = 3; // e.g., "SHA256" - bytes hash = 4; // Hash of complete data + string hash_algorithm = 3; // e.g., "SHA256" + bytes hash = 4; // Hash of complete data } diff --git a/proto/prism/common/types.proto b/proto/prism/common/types.proto index 5daebc9e0..5c794bed8 100644 --- a/proto/prism/common/types.proto +++ b/proto/prism/common/types.proto @@ -11,18 +11,18 @@ message Timestamp { // UUID (standard 128-bit UUID) message UUID { - string value = 1; // UUID string format + string value = 1; // UUID string format } // Cursor for pagination message Cursor { - bytes token = 1; // Opaque pagination token + bytes token = 1; // Opaque pagination token } // Time range message TimeRange { - int64 start_millis = 1; // Inclusive - int64 end_millis = 2; // Exclusive + int64 start_millis = 1; // Inclusive + int64 end_millis = 2; // Exclusive } // Tags for filtering/indexing diff --git a/proto/prism/control_plane.proto b/proto/prism/control_plane.proto index be8ea94e6..82d7eaa45 100644 --- a/proto/prism/control_plane.proto +++ b/proto/prism/control_plane.proto @@ -2,10 +2,10 @@ syntax = "proto3"; package prism; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism"; - import "prism/options.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism"; + // ControlPlane service provides bidirectional gRPC protocol between // prism-admin and managed components (prism-proxy, prism-launcher). // @@ -79,7 +79,7 @@ service ControlPlane { // RevokeProcess removes process assignment from launcher with graceful timeout. rpc RevokeProcess(ProcessRevocation) returns (ProcessRevocationAck) { option (idempotent) = true; - option (timeout_ms) = 35000; // 30s graceful + 5s overhead + option (timeout_ms) = 35000; // 30s graceful + 5s overhead } } @@ -88,10 +88,10 @@ service ControlPlane { // ==================================================================== message ProxyRegistration { - string proxy_id = 1; // Unique proxy identifier (proxy-01) - string address = 2; // Proxy gRPC address (proxy-01.prism.local:8980) - string region = 3; // Deployment region (us-west-2) - string version = 4; // Proxy version (0.1.0) + string proxy_id = 1; // Unique proxy identifier (proxy-01) + string address = 2; // Proxy gRPC address (proxy-01.prism.local:8980) + string region = 3; // Deployment region (us-west-2) + string version = 4; // Proxy version (0.1.0) repeated string capabilities = 5; // Supported patterns (keyvalue, pubsub) map metadata = 6; // Custom labels } @@ -100,14 +100,14 @@ message ProxyRegistrationAck { bool success = 1; string message = 2; repeated NamespaceAssignment initial_namespaces = 3; // Pre-assigned namespaces - repeated PartitionRange partition_ranges = 4; // Assigned partition ranges + repeated PartitionRange partition_ranges = 4; // Assigned partition ranges } message NamespaceAssignment { string namespace = 1; - int32 partition_id = 2; // Partition ID (0-255) - NamespaceConfig config = 3; // Full namespace configuration - int64 version = 4; // Config version for idempotency + int32 partition_id = 2; // Partition ID (0-255) + NamespaceConfig config = 3; // Full namespace configuration + int64 version = 4; // Config version for idempotency } message NamespaceConfig { @@ -118,36 +118,36 @@ message NamespaceConfig { } message BackendConfig { - string backend_type = 1; // redis, kafka, nats, postgres, memstore + string backend_type = 1; // redis, kafka, nats, postgres, memstore string connection_string = 2; map credentials = 3; map options = 4; } message PatternConfig { - string pattern_name = 1; // keyvalue, pubsub, multicast_registry + string pattern_name = 1; // keyvalue, pubsub, multicast_registry map settings = 2; repeated string required_interfaces = 3; // Interfaces this pattern requires } message AuthConfig { bool enabled = 1; - string provider = 2; // oidc, jwt, mtls + string provider = 2; // oidc, jwt, mtls map options = 3; } message CreateNamespaceRequest { string namespace = 1; - string requesting_proxy = 2; // Proxy ID handling client request + string requesting_proxy = 2; // Proxy ID handling client request NamespaceConfig config = 3; - string principal = 4; // Authenticated user creating namespace + string principal = 4; // Authenticated user creating namespace } message CreateNamespaceResponse { bool success = 1; string message = 2; int32 assigned_partition = 3; - string assigned_proxy = 4; // Proxy that will handle this namespace + string assigned_proxy = 4; // Proxy that will handle this namespace } message ProxyHeartbeat { @@ -160,7 +160,7 @@ message ProxyHeartbeat { message NamespaceHealth { int32 active_sessions = 1; int64 requests_per_second = 2; - string status = 3; // healthy, degraded, unhealthy + string status = 3; // healthy, degraded, unhealthy } message ResourceUsage { @@ -184,12 +184,12 @@ message NamespaceRevocation { message NamespaceRevocationAck { bool success = 1; string message = 2; - int64 revoked_at = 3; // Unix timestamp when namespace removed + int64 revoked_at = 3; // Unix timestamp when namespace removed } message PartitionRange { - int32 start = 1; // Inclusive - int32 end = 2; // Inclusive + int32 start = 1; // Inclusive + int32 end = 2; // Inclusive } // ==================================================================== @@ -197,12 +197,12 @@ message PartitionRange { // ==================================================================== message LauncherRegistration { - string launcher_id = 1; // Unique launcher identifier (launcher-01) - string address = 2; // Launcher gRPC address (launcher-01.prism.local:7070) - string region = 3; // Deployment region (us-west-2) - string version = 4; // Launcher version (0.1.0) + string launcher_id = 1; // Unique launcher identifier (launcher-01) + string address = 2; // Launcher gRPC address (launcher-01.prism.local:7070) + string region = 3; // Deployment region (us-west-2) + string version = 4; // Launcher version (0.1.0) repeated string capabilities = 5; // Supported process types (pattern, proxy, backend, utility) - int32 max_processes = 6; // Maximum concurrent processes + int32 max_processes = 6; // Maximum concurrent processes repeated string process_types = 7; // Process types this launcher supports map metadata = 8; // Custom labels } @@ -211,15 +211,15 @@ message LauncherRegistrationAck { bool success = 1; string message = 2; repeated ProcessAssignment initial_processes = 3; // Pre-assigned processes - int32 assigned_capacity = 4; // Number of process slots assigned + int32 assigned_capacity = 4; // Number of process slots assigned } message ProcessAssignment { - string process_id = 1; // Unique process identifier - string process_type = 2; // pattern, proxy, backend, utility - string namespace = 3; // Target namespace (if applicable) - ProcessConfig config = 4; // Process-specific configuration - int64 version = 5; // Config version for idempotency + string process_id = 1; // Unique process identifier + string process_type = 2; // pattern, proxy, backend, utility + string namespace = 3; // Target namespace (if applicable) + ProcessConfig config = 4; // Process-specific configuration + int64 version = 5; // Config version for idempotency } message ProcessAssignmentAck { @@ -244,10 +244,10 @@ message ProcessConfig { } message PatternProcessConfig { - string pattern_type = 1; // keyvalue, pubsub, multicast_registry - string isolation_level = 2; // none, namespace, session + string pattern_type = 1; // keyvalue, pubsub, multicast_registry + string isolation_level = 2; // none, namespace, session map slots = 3; // Backend configurations for pattern slots - map settings = 4; // Pattern-specific settings + map settings = 4; // Pattern-specific settings } message ProxyProcessConfig { @@ -259,14 +259,14 @@ message ProxyProcessConfig { } message BackendProcessConfig { - string backend_type = 1; // redis, kafka, nats, postgres + string backend_type = 1; // redis, kafka, nats, postgres string connection_string = 2; map credentials = 3; map driver_options = 4; } message UtilityProcessConfig { - string utility_type = 1; // log-collector, metrics-exporter, health-monitor + string utility_type = 1; // log-collector, metrics-exporter, health-monitor map settings = 2; repeated string target_processes = 3; // Process IDs this utility monitors/manages } @@ -279,22 +279,22 @@ message LauncherHeartbeatRequest { } message ProcessHealth { - string status = 1; // running, starting, stopping, failed, stopped - int32 pid = 2; // Process ID - int32 restart_count = 3; // Number of restarts - int32 error_count = 4; // Cumulative error count - int64 memory_mb = 5; // Memory usage in MB - int64 uptime_seconds = 6; // Seconds since process started - string last_error = 7; // Last error message (if any) - float cpu_percent = 8; // CPU utilization percentage + string status = 1; // running, starting, stopping, failed, stopped + int32 pid = 2; // Process ID + int32 restart_count = 3; // Number of restarts + int32 error_count = 4; // Cumulative error count + int64 memory_mb = 5; // Memory usage in MB + int64 uptime_seconds = 6; // Seconds since process started + string last_error = 7; // Last error message (if any) + float cpu_percent = 8; // CPU utilization percentage } message LauncherResourceUsage { - int32 process_count = 1; // Current process count - int32 max_processes = 2; // Maximum capacity - int64 total_memory_mb = 3; // Total memory used by all processes - float cpu_percent = 4; // CPU utilization percentage - int32 available_slots = 5; // Remaining process slots + int32 process_count = 1; // Current process count + int32 max_processes = 2; // Maximum capacity + int64 total_memory_mb = 3; // Total memory used by all processes + float cpu_percent = 4; // CPU utilization percentage + int32 available_slots = 5; // Remaining process slots } message ProcessRevocation { @@ -306,8 +306,8 @@ message ProcessRevocation { message ProcessRevocationAck { bool success = 1; string message = 2; - int64 stopped_at = 3; // Unix timestamp when process stopped - int32 exit_code = 4; // Process exit code + int64 stopped_at = 3; // Unix timestamp when process stopped + int32 exit_code = 4; // Process exit code } // ==================================================================== @@ -317,5 +317,5 @@ message ProcessRevocationAck { message HeartbeatAck { bool success = 1; string message = 2; - int64 server_timestamp = 3; // Server's current timestamp for clock sync + int64 server_timestamp = 3; // Server's current timestamp for clock sync } diff --git a/proto/prism/interfaces/keyvalue/keyvalue_basic.proto b/proto/prism/interfaces/keyvalue/keyvalue_basic.proto index 401f6daf5..cb773dbeb 100644 --- a/proto/prism/interfaces/keyvalue/keyvalue_basic.proto +++ b/proto/prism/interfaces/keyvalue/keyvalue_basic.proto @@ -2,10 +2,10 @@ syntax = "proto3"; package prism.interfaces.keyvalue; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces/keyvalue"; - import "prism/common/types.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces/keyvalue"; + // KeyValueBasicInterface defines core key-value operations. // ALL backends implementing key-value storage MUST support this interface. // diff --git a/proto/prism/interfaces/keyvalue/keyvalue_batch.proto b/proto/prism/interfaces/keyvalue/keyvalue_batch.proto index 1b952fcc7..84629d419 100644 --- a/proto/prism/interfaces/keyvalue/keyvalue_batch.proto +++ b/proto/prism/interfaces/keyvalue/keyvalue_batch.proto @@ -2,10 +2,10 @@ syntax = "proto3"; package prism.interfaces.keyvalue; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces/keyvalue"; - import "prism/interfaces/keyvalue/keyvalue_basic.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces/keyvalue"; + // KeyValueBatchInterface defines bulk operations for key-value storage. // This interface is OPTIONAL and provides efficiency gains for backends // that support native batch operations (e.g., Redis MGET/MSET, DynamoDB BatchGetItem). diff --git a/proto/prism/interfaces/lifecycle.proto b/proto/prism/interfaces/lifecycle.proto index ee6baa1f1..6d63cb684 100644 --- a/proto/prism/interfaces/lifecycle.proto +++ b/proto/prism/interfaces/lifecycle.proto @@ -2,10 +2,10 @@ syntax = "proto3"; package prism.interfaces; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces"; - import "google/protobuf/struct.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces"; + // LifecycleInterface defines pattern lifecycle management operations. // ALL pattern executors MUST implement this interface for initialization, // health checks, and graceful shutdown. @@ -169,7 +169,7 @@ message HealthCheckResponse { // Health status enumeration enum HealthStatus { HEALTH_STATUS_UNSPECIFIED = 0; - HEALTH_STATUS_HEALTHY = 1; // Pattern is healthy - HEALTH_STATUS_DEGRADED = 2; // Pattern is running but unhealthy - HEALTH_STATUS_UNHEALTHY = 3; // Pattern is not functioning + HEALTH_STATUS_HEALTHY = 1; // Pattern is healthy + HEALTH_STATUS_DEGRADED = 2; // Pattern is running but unhealthy + HEALTH_STATUS_UNHEALTHY = 3; // Pattern is not functioning } diff --git a/proto/prism/interfaces/proxy_control_plane.proto b/proto/prism/interfaces/proxy_control_plane.proto index 7e3520b42..588460d28 100644 --- a/proto/prism/interfaces/proxy_control_plane.proto +++ b/proto/prism/interfaces/proxy_control_plane.proto @@ -2,11 +2,10 @@ syntax = "proto3"; package prism.interfaces; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces"; - -import "google/protobuf/struct.proto"; import "prism/interfaces/lifecycle.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism/interfaces"; + // ProxyControlPlane is the service that patterns connect to. // The proxy runs this service, and patterns connect as clients. // diff --git a/proto/prism/launcher/launcher.proto b/proto/prism/launcher/launcher.proto index 6343bcf31..18c96d2d2 100644 --- a/proto/prism/launcher/launcher.proto +++ b/proto/prism/launcher/launcher.proto @@ -6,218 +6,224 @@ option go_package = "github.com/jrepp/prism/gen/go/prism/launcher"; // PatternLauncher service manages pattern process lifecycle service PatternLauncher { - // Launch or get existing pattern process - rpc LaunchPattern(LaunchRequest) returns (LaunchResponse); + // Launch or get existing pattern process + rpc LaunchPattern(LaunchRequest) returns (LaunchResponse); - // List all running pattern processes - rpc ListPatterns(ListPatternsRequest) returns (ListPatternsResponse); + // List all running pattern processes + rpc ListPatterns(ListPatternsRequest) returns (ListPatternsResponse); - // Terminate a pattern process - rpc TerminatePattern(TerminateRequest) returns (TerminateResponse); + // Terminate a pattern process + rpc TerminatePattern(TerminateRequest) returns (TerminateResponse); - // Health check for launcher and all processes - rpc Health(HealthRequest) returns (HealthResponse); + // Health check for launcher and all processes + rpc Health(HealthRequest) returns (HealthResponse); - // Get detailed status of a specific process - rpc GetProcessStatus(GetProcessStatusRequest) returns (GetProcessStatusResponse); + // Get detailed status of a specific process + rpc GetProcessStatus(GetProcessStatusRequest) returns (GetProcessStatusResponse); } // LaunchRequest initiates or retrieves a pattern process message LaunchRequest { - // Pattern name (e.g., "consumer", "producer") - string pattern_name = 1; + // Pattern name (e.g., "consumer", "producer") + string pattern_name = 1; - // Isolation level for this pattern - IsolationLevel isolation = 2; + // Isolation level for this pattern + IsolationLevel isolation = 2; - // Namespace for NAMESPACE isolation - string namespace = 3; + // Namespace for NAMESPACE isolation + string namespace = 3; - // Session ID for SESSION isolation - string session_id = 4; + // Session ID for SESSION isolation + string session_id = 4; - // Pattern-specific configuration - map config = 5; + // Pattern-specific configuration + map config = 5; - // Optional: override grace period (seconds) - int64 grace_period_secs = 6; + // Optional: override grace period (seconds) + int64 grace_period_secs = 6; } // LaunchResponse contains process details message LaunchResponse { - // Unique process ID - string process_id = 1; + // Unique process ID + string process_id = 1; - // Current process state - ProcessState state = 2; + // Current process state + ProcessState state = 2; - // gRPC address to connect to pattern - string address = 3; + // gRPC address to connect to pattern + string address = 3; - // Health status - bool healthy = 4; + // Health status + bool healthy = 4; - // Error message if launch failed - string error = 5; + // Error message if launch failed + string error = 5; } // ListPatternsRequest filters pattern list message ListPatternsRequest { - // Optional: filter by pattern name - string pattern_name = 1; + // Optional: filter by pattern name + string pattern_name = 1; - // Optional: filter by namespace - string namespace = 2; + // Optional: filter by namespace + string namespace = 2; - // Optional: filter by state - ProcessState state = 3; + // Optional: filter by state + ProcessState state = 3; } // ListPatternsResponse returns all matching patterns message ListPatternsResponse { - repeated PatternInfo patterns = 1; + repeated PatternInfo patterns = 1; - // Total count of all processes (before filtering) - int32 total_count = 2; + // Total count of all processes (before filtering) + int32 total_count = 2; } // PatternInfo describes a running pattern process message PatternInfo { - // Pattern name - string pattern_name = 1; + // Pattern name + string pattern_name = 1; - // Process ID - string process_id = 2; + // Process ID + string process_id = 2; - // Current state - ProcessState state = 3; + // Current state + ProcessState state = 3; - // gRPC address - string address = 4; + // gRPC address + string address = 4; - // Health status - bool healthy = 5; + // Health status + bool healthy = 5; - // Uptime in seconds - int64 uptime_seconds = 6; + // Uptime in seconds + int64 uptime_seconds = 6; - // Namespace (for NAMESPACE isolation) - string namespace = 7; + // Namespace (for NAMESPACE isolation) + string namespace = 7; - // Session ID (for SESSION isolation) - string session_id = 8; + // Session ID (for SESSION isolation) + string session_id = 8; - // Last error message - string last_error = 9; + // Last error message + string last_error = 9; - // Error count - int32 error_count = 10; + // Error count + int32 error_count = 10; - // Restart count - int32 restart_count = 11; + // Restart count + int32 restart_count = 11; - // PID (process ID) - int32 pid = 12; + // PID (process ID) + int32 pid = 12; } // TerminateRequest stops a pattern process message TerminateRequest { - // Process ID to terminate - string process_id = 1; + // Process ID to terminate + string process_id = 1; - // Grace period in seconds (overrides default) - int64 grace_period_secs = 2; + // Grace period in seconds (overrides default) + int64 grace_period_secs = 2; - // Force kill if true (SIGKILL) - bool force = 3; + // Force kill if true (SIGKILL) + bool force = 3; } // TerminateResponse confirms termination message TerminateResponse { - // Success status - bool success = 1; + // Success status + bool success = 1; - // Error message if failed - string error = 2; + // Error message if failed + string error = 2; } // HealthRequest checks launcher health message HealthRequest { - // Optional: include detailed process info - bool include_processes = 1; + // Optional: include detailed process info + bool include_processes = 1; } // HealthResponse reports launcher health message HealthResponse { - // Overall health status - bool healthy = 1; + // Overall health status + bool healthy = 1; - // Total processes - int32 total_processes = 2; + // Total processes + int32 total_processes = 2; - // Running processes - int32 running_processes = 3; + // Running processes + int32 running_processes = 3; - // Terminating processes - int32 terminating_processes = 4; + // Terminating processes + int32 terminating_processes = 4; - // Failed processes - int32 failed_processes = 5; + // Failed processes + int32 failed_processes = 5; - // Isolation level distribution - map isolation_distribution = 6; + // Isolation level distribution + map isolation_distribution = 6; - // Detailed process list (if requested) - repeated PatternInfo processes = 7; + // Detailed process list (if requested) + repeated PatternInfo processes = 7; - // Launcher uptime in seconds - int64 uptime_seconds = 8; + // Launcher uptime in seconds + int64 uptime_seconds = 8; } // GetProcessStatusRequest retrieves process details message GetProcessStatusRequest { - // Process ID to query - string process_id = 1; + // Process ID to query + string process_id = 1; } // GetProcessStatusResponse returns process status message GetProcessStatusResponse { - // Process info (nil if not found) - PatternInfo process = 1; + // Process info (nil if not found) + PatternInfo process = 1; - // Not found flag - bool not_found = 2; + // Not found flag + bool not_found = 2; } // IsolationLevel defines process isolation strategy enum IsolationLevel { - // All requests share the same process - ISOLATION_NONE = 0; + // Unspecified isolation level (defaults to NONE) + ISOLATION_LEVEL_UNSPECIFIED = 0; - // Each namespace gets its own process - ISOLATION_NAMESPACE = 1; + // All requests share the same process + ISOLATION_NONE = 1; - // Each session gets its own process - ISOLATION_SESSION = 2; + // Each namespace gets its own process + ISOLATION_NAMESPACE = 2; + + // Each session gets its own process + ISOLATION_SESSION = 3; } // ProcessState represents lifecycle state enum ProcessState { - // Process is initializing - STATE_STARTING = 0; + // Unspecified state + STATE_UNSPECIFIED = 0; + + // Process is initializing + STATE_STARTING = 1; - // Process is running and healthy - STATE_RUNNING = 1; + // Process is running and healthy + STATE_RUNNING = 2; - // Process is shutting down - STATE_TERMINATING = 2; + // Process is shutting down + STATE_TERMINATING = 3; - // Process has stopped, awaiting cleanup - STATE_TERMINATED = 3; + // Process has stopped, awaiting cleanup + STATE_TERMINATED = 4; - // Process failed and needs restart - STATE_FAILED = 4; + // Process failed and needs restart + STATE_FAILED = 5; - // Process cleanup completed - STATE_FINISHED = 5; + // Process cleanup completed + STATE_FINISHED = 6; } diff --git a/proto/prism/options.proto b/proto/prism/options.proto index 487c3c6fc..92add6f5c 100644 --- a/proto/prism/options.proto +++ b/proto/prism/options.proto @@ -2,10 +2,10 @@ syntax = "proto3"; package prism; -option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism"; - import "google/protobuf/descriptor.proto"; +option go_package = "github.com/jrepp/prism-data-layer/proto/gen/prism"; + // // Message-level options (for data models) // @@ -32,7 +32,7 @@ extend google.protobuf.MessageOptions { string consistency = 50006; // Retention policy - int32 retention_days = 50007; // 0 = keep forever + int32 retention_days = 50007; // 0 = keep forever // Caching bool enable_cache = 50008; @@ -62,7 +62,7 @@ extend google.protobuf.FieldOptions { bool access_audit = 50104; // Validation rules - string validation = 50105; // "email" | "uuid" | "url" | "regex:..." | "min:N" | "max:N" + string validation = 50105; // "email" | "uuid" | "url" | "regex:..." | "min:N" | "max:N" // Max length for strings int32 max_length = 50106;