syntax = "proto3";

package hl7v2.v1;

option go_package = "github.com/EffortlessMetrics/hl7v2-rs/gen/go/hl7v2/v1;hl7v2v1";
option java_package = "com.hl7v2rs.api.v1";
option java_multiple_files = true;

// HL7v2 Service provides gRPC endpoints for HL7 v2 message processing
service HL7Service {
  // Parse an HL7 v2 message
  rpc Parse(ParseRequest) returns (ParseResponse);

  // Parse multiple messages in a stream
  rpc ParseStream(stream ParseStreamRequest) returns (stream ParseStreamResponse);

  // Validate a message against a profile
  rpc Validate(ValidateRequest) returns (ValidateResponse);

  // Lint an inline profile without applying it to a message
  rpc ProfileLint(ProfileLintRequest) returns (ProfileLintResponse);

  // Explain an inline profile as structured evidence
  rpc ProfileExplain(ProfileExplainRequest) returns (ProfileExplainResponse);

  // Test inline fixtures against an inline profile as structured evidence
  rpc ProfileTest(ProfileTestRequest) returns (ProfileTestResponse);

  // Redact a message with a safe-analysis policy, then validate it
  rpc ValidateRedacted(ValidateRedactedRequest) returns (ValidateRedactedResponse);

  // Create a redacted evidence bundle under the configured server bundle root
  rpc CreateEvidenceBundle(CreateEvidenceBundleRequest) returns (CreateEvidenceBundleResponse);

  // Replay and verify a redacted evidence bundle under the configured server bundle root
  rpc ReplayEvidenceBundle(ReplayEvidenceBundleRequest) returns (ReplayEvidenceBundleResponse);

  // Summarize an inline corpus without reading caller-supplied filesystem paths
  rpc CorpusSummarize(CorpusSummarizeRequest) returns (CorpusSummarizeResponse);

  // Fingerprint an inline corpus without reading caller-supplied filesystem paths
  rpc CorpusFingerprint(CorpusFingerprintRequest) returns (CorpusFingerprintResponse);

  // Diff two inline corpora without reading caller-supplied filesystem paths
  rpc CorpusDiff(CorpusDiffRequest) returns (CorpusDiffResponse);

  // Generate an acknowledgment (ACK) message
  rpc GenerateAck(GenerateAckRequest) returns (GenerateAckResponse);

  // Normalize a message
  rpc Normalize(NormalizeRequest) returns (NormalizeResponse);

  // Health check
  rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse);
}

// Parse Request
message ParseRequest {
  // HL7 message bytes
  bytes message = 1;

  // Whether message is MLLP-framed
  bool mllp_framed = 2;

  // Parse options
  ParseOptions options = 3;
}

message ParseStreamRequest {
  // HL7 message bytes
  bytes message = 1;

  // Whether message is MLLP-framed
  bool mllp_framed = 2;

  // Parse options
  ParseOptions options = 3;
}

message ParseOptions {
  // Strict parsing mode
  bool strict = 1;

  // Expected HL7 version
  string expected_version = 2;
}

// Parse Response
message ParseResponse {
  // Whether parsing succeeded
  bool success = 1;

  // Parsed message (if successful)
  Message message = 2;

  // Errors (if any)
  repeated Error errors = 3;

  // Metadata
  MessageMetadata metadata = 4;
}

message ParseStreamResponse {
  // Whether parsing succeeded
  bool success = 1;

  // Parsed message (if successful)
  Message message = 2;

  // Errors (if any)
  repeated Error errors = 3;

  // Metadata
  MessageMetadata metadata = 4;
}

// Message representation
message Message {
  // Delimiters used
  Delimiters delimiters = 1;

  // Segments
  repeated Segment segments = 2;
}

// Delimiters
message Delimiters {
  string field = 1;
  string component = 2;
  string repetition = 3;
  string escape = 4;
  string subcomponent = 5;
}

// Segment
message Segment {
  // Segment ID (e.g., "MSH", "PID")
  string id = 1;

  // Fields
  repeated Field fields = 2;

  // Sequence number (for repeated segments)
  int32 sequence = 3;
}

// Field
message Field {
  // Field presence
  enum Presence {
    PRESENCE_UNSPECIFIED = 0;
    PRESENCE_MISSING = 1;
    PRESENCE_EMPTY = 2;
    PRESENCE_NULL = 3;
    PRESENCE_VALUE = 4;
  }

  Presence presence = 1;

  // Simple value (for non-repeating, non-component fields)
  optional string value = 2;

  // Repetitions (for repeating fields)
  repeated Repetition repetitions = 3;
}

// Repetition
message Repetition {
  // Simple value
  optional string value = 1;

  // Components
  repeated Component components = 2;
}

// Component
message Component {
  // Component value
  optional string value = 1;

  // Subcomponents
  repeated string subcomponents = 2;
}

// Message Metadata
message MessageMetadata {
  // Message type (e.g., "ADT^A01")
  string message_type = 1;

  // HL7 version (e.g., "2.5")
  string version = 2;

  // Message control ID
  string control_id = 3;

  // Sending facility
  string sending_facility = 4;

  // Receiving facility
  string receiving_facility = 5;
}

// Validate Request
message ValidateRequest {
  // HL7 message bytes
  bytes message = 1;

  // Inline HL7v2 profile YAML content
  string profile = 2;

  // Whether message is MLLP-framed
  bool mllp_framed = 3;

  // Validation options
  ValidationOptions options = 4;

  // Optional validation evidence schema version.
  //
  // Omitted or 1 preserves the legacy response fields. 2 includes the
  // validation_report_v2 field with embedded provenance.
  int32 report_schema_version = 5;
}

message ValidationOptions {
  // Fail on warnings
  bool fail_on_warning = 1;

  // Strict mode
  bool strict = 2;
}

// Profile lint request.
message ProfileLintRequest {
  // Inline HL7v2 profile YAML content
  string profile = 1;

  // Optional profile lint evidence schema version.
  //
  // Omitted or 1 preserves the default report fields. 2 includes the
  // profile_lint_report_v2 field with embedded provenance.
  int32 report_schema_version = 2;
}

// Profile lint response.
message ProfileLintResponse {
  // Stable profile lint report fields shared with Rust, CLI, and Python.
  ProfileLintReport profile_lint_report = 1;

  // Opt-in profile lint report with embedded evidence provenance.
  ProfileLintReportV2 profile_lint_report_v2 = 2;
}

// Stable profile lint report artifact.
message ProfileLintReport {
  // Whether the profile has no lint errors.
  bool valid = 1;

  // Number of error-level lint issues.
  uint32 error_count = 2;

  // Number of warning-level lint issues.
  uint32 warning_count = 3;

  // Total number of lint issues.
  uint32 issue_count = 4;

  // Lint findings.
  repeated ProfileLintIssue issues = 5;
}

// Profile lint report v2 artifact with embedded evidence provenance.
message ProfileLintReportV2 {
  // Evidence artifact schema version.
  string schema_version = 1;

  // Producer surface that generated this profile lint report.
  string tool_name = 2;

  // Semantic version of the producing crate or binding package.
  string tool_version = 3;

  // Whether the profile has no lint errors.
  bool valid = 4;

  // Number of error-level lint issues.
  uint32 error_count = 5;

  // Number of warning-level lint issues.
  uint32 warning_count = 6;

  // Total number of lint issues.
  uint32 issue_count = 7;

  // Lint findings.
  repeated ProfileLintIssue issues = 8;
}

// A single profile lint finding.
message ProfileLintIssue {
  // Stable lint code.
  string code = 1;

  // Finding severity, usually "error" or "warning".
  string severity = 2;

  // Profile path or YAML location, when available.
  optional string path = 3;

  // Human-readable explanation. This must not include raw profile text.
  string message = 4;
}

// Profile explain request.
message ProfileExplainRequest {
  // Inline HL7v2 profile YAML content
  string profile = 1;

  // Optional profile explain evidence schema version.
  //
  // Omitted or 1 preserves the default report fields. 2 includes the
  // profile_explain_report_v2 field with embedded provenance.
  int32 report_schema_version = 2;
}

// Profile explain response.
message ProfileExplainResponse {
  // Stable profile explain report fields shared with Rust, CLI, and Python.
  ProfileExplainReport profile_explain_report = 1;

  // Opt-in profile explain report with embedded evidence provenance.
  ProfileExplainReportV2 profile_explain_report_v2 = 2;
}

// Stable profile explain report artifact.
message ProfileExplainReport {
  string profile = 1;
  string profile_sha256 = 2;
  string message_structure = 3;
  string version = 4;
  optional string message_type = 5;
  optional string parent = 6;
  ProfileExplainSummary summary = 7;
  repeated ProfileExplainSegment segments = 8;
  repeated ProfileExplainRequiredField required_fields = 9;
  repeated ProfileExplainConstraint field_constraints = 10;
  repeated ProfileExplainLengthRule length_rules = 11;
  repeated ProfileExplainDatatypeRule datatype_rules = 12;
  repeated ProfileExplainValueSet value_sets = 13;
  ProfileExplainRules rules = 14;
  repeated ProfileExplainTable hl7_tables = 15;
  repeated string table_precedence = 16;
  ProfileExplainExpressionGuardrails expression_guardrails = 17;
  ProfileExplainLintSummary lint = 18;
}

// Profile explain report v2 artifact with embedded evidence provenance.
message ProfileExplainReportV2 {
  string schema_version = 1;
  string tool_name = 2;
  string tool_version = 3;
  ProfileExplainReport report = 4;
}

message ProfileExplainSummary {
  uint32 segment_count = 1;
  uint32 required_field_count = 2;
  uint32 field_constraint_count = 3;
  uint32 length_rule_count = 4;
  uint32 datatype_rule_count = 5;
  uint32 advanced_datatype_rule_count = 6;
  uint32 value_set_count = 7;
  uint32 cross_field_rule_count = 8;
  uint32 temporal_rule_count = 9;
  uint32 contextual_rule_count = 10;
  uint32 custom_rule_count = 11;
  uint32 hl7_table_count = 12;
}

message ProfileExplainSegment {
  string id = 1;
}

message ProfileExplainRequiredField {
  string path = 1;
  bool conditional = 2;
}

message ProfileExplainConstraint {
  string path = 1;
  bool required = 2;
  bool conditional = 3;
  optional uint32 component_min = 4;
  optional uint32 component_max = 5;
  uint32 allowed_value_count = 6;
  repeated string allowed_values = 7;
  optional string pattern = 8;
}

message ProfileExplainLengthRule {
  string path = 1;
  optional uint32 max = 2;
  optional string policy = 3;
}

message ProfileExplainDatatypeRule {
  string path = 1;
  string datatype = 2;
  string kind = 3;
  optional string pattern = 4;
  optional uint32 min_length = 5;
  optional uint32 max_length = 6;
  optional string format = 7;
  optional string checksum = 8;
}

message ProfileExplainValueSet {
  string name = 1;
  string path = 2;
  string source = 3;
  uint32 inline_code_count = 4;
  uint32 table_code_count = 5;
}

message ProfileExplainRules {
  repeated ProfileExplainRule cross_field = 1;
  repeated ProfileExplainRule temporal = 2;
  repeated ProfileExplainRule contextual = 3;
  repeated ProfileExplainRule custom = 4;
}

message ProfileExplainRule {
  string id = 1;
  string description = 2;
}

message ProfileExplainTable {
  string id = 1;
  string name = 2;
  string version = 3;
  uint32 code_count = 4;
}

message ProfileExplainExpressionGuardrails {
  optional uint32 max_depth = 1;
  optional uint32 max_length = 2;
  bool allow_custom_scripts = 3;
}

message ProfileExplainLintSummary {
  bool valid = 1;
  uint32 error_count = 2;
  uint32 warning_count = 3;
  uint32 issue_count = 4;
  repeated ProfileLintIssue ignored_or_unsupported = 5;
}

// Profile fixture test request.
message ProfileTestRequest {
  // Inline HL7v2 profile YAML content
  string profile = 1;

  // Inline fixture messages. The service does not read filesystem paths from
  // this request.
  repeated ProfileTestFixture fixtures = 2;

  // Optional profile test evidence schema version.
  //
  // Omitted or 1 preserves the default report fields. 2 includes the
  // profile_test_report_v2 field with embedded provenance.
  int32 report_schema_version = 3;
}

// Caller-supplied in-memory profile fixture.
message ProfileTestFixture {
  enum Expectation {
    EXPECTATION_UNSPECIFIED = 0;
    EXPECTATION_VALID = 1;
    EXPECTATION_INVALID = 2;
  }

  // Stable fixture label. This is not a filesystem path and must be safe to
  // echo in evidence.
  string name = 1;

  // Raw HL7 message bytes. Plain HL7 and MLLP-framed messages are accepted.
  bytes message = 2;

  // Whether this fixture is expected to validate or fail validation.
  Expectation expectation = 3;

  // Whether message is MLLP-framed.
  bool mllp_framed = 4;

  // Optional expected validation report subset as JSON.
  optional string expected_report_json = 5;
}

// Profile fixture test response.
message ProfileTestResponse {
  // Stable profile test report fields shared with Rust, CLI, and Python.
  ProfileTestReport profile_test_report = 1;

  // Opt-in profile test report with embedded evidence provenance.
  ProfileTestReportV2 profile_test_report_v2 = 2;
}

// Stable profile test report artifact.
message ProfileTestReport {
  string profile = 1;
  string fixtures = 2;
  bool valid = 3;
  uint32 case_count = 4;
  uint32 passed_count = 5;
  uint32 failed_count = 6;
  repeated ProfileTestCaseReport cases = 7;
}

// Profile test report v2 artifact with embedded evidence provenance.
message ProfileTestReportV2 {
  string schema_version = 1;
  string tool_name = 2;
  string tool_version = 3;
  ProfileTestReport report = 4;
}

message ProfileTestCaseReport {
  string name = 1;
  string path = 2;
  string expectation = 3;
  bool passed = 4;
  string message = 5;
  ValidationReport validation_report = 6;
  ExpectedReportComparison expected_report = 7;
}

message ExpectedReportComparison {
  string path = 1;
  bool matched = 2;
  optional string message = 3;
}

// Validate Response
message ValidateResponse {
  // Whether validation passed
  bool valid = 1;

  // Errors
  repeated ValidationIssue errors = 2;

  // Warnings
  repeated ValidationIssue warnings = 3;

  // Summary
  ValidationSummary summary = 4;

  // Stable validation report fields shared with CLI, REST, Rust, and Python
  ValidationReport validation_report = 5;

  // Opt-in validation report with embedded evidence provenance
  ValidationReportV2 validation_report_v2 = 6;
}

// Validate and redact request.
message ValidateRedactedRequest {
  // HL7 message bytes
  bytes message = 1;

  // Inline HL7v2 profile YAML content
  string profile = 2;

  // Inline safe-analysis redaction policy in TOML format
  string redaction_policy = 3;

  // Whether message is MLLP-framed
  bool mllp_framed = 4;

  // Whether to include the redacted HL7 payload in the response
  bool include_redacted_hl7 = 5;

  // Optional validation evidence schema version.
  //
  // Omitted or 1 preserves the default response fields. 2 includes the
  // validation_report_v2 field with embedded provenance.
  int32 report_schema_version = 6;

  // Optional redaction receipt evidence schema version.
  //
  // Omitted or 1 preserves the default receipt fields. 2 includes the
  // redaction_receipt_v2 field with embedded provenance.
  int32 redaction_receipt_schema_version = 7;

  // Optional quarantine output summary schema version.
  //
  // Omitted or 1 preserves the default quarantine summary. 2 includes the
  // quarantine_v2 field with embedded provenance when quarantine output is
  // configured and validation fails.
  int32 quarantine_schema_version = 8;
}

// Validate and redact response.
message ValidateRedactedResponse {
  // Validation report generated from the redacted message
  ValidationReport validation_report = 1;

  // Opt-in validation report with embedded evidence provenance
  ValidationReportV2 validation_report_v2 = 2;

  // Receipt describing redaction actions applied before validation
  RedactionReceipt redaction_receipt = 3;

  // Opt-in redaction receipt with embedded evidence provenance
  RedactionReceiptV2 redaction_receipt_v2 = 4;

  // Redacted HL7 payload, included only when requested
  optional bytes redacted_hl7 = 5;

  // Quarantine output summary when configured and validation failed
  QuarantineOutputSummary quarantine = 6;

  // Opt-in quarantine output with embedded evidence provenance
  QuarantineOutputSummaryV2 quarantine_v2 = 7;
}

// Stable redaction receipt artifact.
message RedactionReceipt {
  // Whether any configured PHI-bearing field was removed or hashed
  bool phi_removed = 1;

  // Hash algorithm used by hash redaction actions
  string hash_algorithm = 2;

  // Per-rule redaction receipts
  repeated RedactionActionReceipt actions = 3;
}

// Redaction receipt v2 artifact with embedded evidence provenance.
message RedactionReceiptV2 {
  // Evidence artifact schema version
  string schema_version = 1;

  // Producer surface that generated this receipt
  string tool_name = 2;

  // Semantic version of the producing crate or binding package
  string tool_version = 3;

  // Whether any configured PHI-bearing field was removed or hashed
  bool phi_removed = 4;

  // Hash algorithm used by hash redaction actions
  string hash_algorithm = 5;

  // Per-rule redaction receipts
  repeated RedactionActionReceipt actions = 6;
}

// Stable quarantine output summary artifact.
message QuarantineOutputSummary {
  // Quarantine output contract version
  string quarantine_version = 1;

  // Output directory relative to the configured quarantine root
  string output_dir = 2;

  // Stable reason for quarantine output, for example validation_error
  string reason = 3;

  // Number of validation issues that triggered quarantine output
  uint32 validation_issue_count = 4;

  // Quarantine-relative artifact names written by the server
  repeated string artifacts = 5;
}

// Quarantine output summary v2 artifact with embedded evidence provenance.
message QuarantineOutputSummaryV2 {
  // Evidence artifact schema version
  string schema_version = 1;

  // Producer surface that generated this summary
  string tool_name = 2;

  // Semantic version of the producing crate or binding package
  string tool_version = 3;

  // Quarantine output contract version
  string quarantine_version = 4;

  // Output directory relative to the configured quarantine root
  string output_dir = 5;

  // Stable reason for quarantine output, for example validation_error
  string reason = 6;

  // Number of validation issues that triggered quarantine output
  uint32 validation_issue_count = 7;

  // Quarantine-relative artifact names written by the server
  repeated string artifacts = 8;
}

// Per-rule redaction action receipt.
message RedactionActionReceipt {
  // HL7 path covered by this policy action
  string path = 1;

  // Policy action: hash, drop, or retain
  string action = 2;

  // Policy reason for the action
  string reason = 3;

  // Number of matching values affected by this action
  uint32 matched_count = 4;

  // Whether missing matches are acceptable
  bool optional = 5;

  // Action status: applied, retained, or not_found
  string status = 6;
}

// Server evidence bundle creation request.
message CreateEvidenceBundleRequest {
  // HL7 message bytes
  bytes message = 1;

  // Inline HL7v2 profile YAML content
  string profile = 2;

  // Inline safe-analysis redaction policy in TOML format
  string redaction_policy = 3;

  // Caller-supplied bundle identifier relative to the configured server bundle
  // root. The service validates this as a relative identifier and does not
  // expose it in the response.
  string bundle_id = 4;

  // Whether message is MLLP-framed
  bool mllp_framed = 5;

  // Optional bundle-internal artifact schema version.
  //
  // Omitted or 1 writes default bundle artifact shapes. 2 writes bundle
  // internals with embedded evidence provenance.
  int32 bundle_artifact_schema_version = 6;
}

// Server evidence bundle creation response.
message CreateEvidenceBundleResponse {
  // Stable evidence bundle summary fields shared with CLI, REST, Rust, and
  // Python.
  EvidenceBundleSummary summary = 1;
}

// Server evidence bundle replay request.
message ReplayEvidenceBundleRequest {
  // Caller-supplied bundle identifier relative to the configured server bundle
  // root. The service validates this as a relative identifier and does not
  // expose it in the response.
  string bundle_id = 1;

  // Optional replay evidence schema version.
  //
  // Omitted or 1 preserves the default replay report fields. 2 includes the
  // replay_report_v2 field with embedded evidence schema provenance.
  int32 replay_report_schema_version = 2;
}

// Server evidence bundle replay response.
message ReplayEvidenceBundleResponse {
  // Stable replay report fields shared with CLI, REST, Rust, and Python.
  EvidenceReplayReport replay_report = 1;

  // Opt-in replay report with embedded evidence schema provenance.
  EvidenceReplayReportV2 replay_report_v2 = 2;
}

// Stable evidence bundle summary artifact.
message EvidenceBundleSummary {
  string bundle_version = 1;
  string output_dir = 2;
  string message_type = 3;
  bool validation_valid = 4;
  uint32 validation_issue_count = 5;
  bool redaction_phi_removed = 6;
  repeated string artifacts = 7;
}

// Stable evidence replay report artifact.
message EvidenceReplayReport {
  string replay_version = 1;
  optional string bundle_version = 2;
  string tool_name = 3;
  string tool_version = 4;
  optional string message_type = 5;
  bool reproduced = 6;
  optional bool validation_valid = 7;
  optional uint32 validation_issue_count = 8;
  repeated EvidenceReplayCheck checks = 9;
  optional ValidationReport validation_report = 10;
}

// Evidence replay report v2 artifact with embedded schema provenance.
message EvidenceReplayReportV2 {
  string schema_version = 1;
  EvidenceReplayReport report = 2;
}

// One replay verification check.
message EvidenceReplayCheck {
  enum Status {
    STATUS_UNSPECIFIED = 0;
    STATUS_PASS = 1;
    STATUS_FAIL = 2;
  }

  string name = 1;
  Status status = 2;
  string message = 3;
}

// Inline corpus summary request.
message CorpusSummarizeRequest {
  // Inline HL7 messages to summarize. The service does not read filesystem
  // paths from this request.
  repeated CorpusMessageInput messages = 1;

  // Optional corpus summary evidence schema version.
  //
  // Omitted or 1 preserves the default summary fields. 2 includes the
  // summary_v2 field with embedded provenance.
  int32 summary_schema_version = 2;
}

// Caller-supplied in-memory corpus message.
message CorpusMessageInput {
  // Optional stable label for parse-error reporting. This is not a filesystem
  // path and must be safe to echo in evidence.
  optional string id = 1;

  // Raw HL7 message bytes. Plain HL7 and MLLP-framed messages are accepted.
  bytes message = 2;
}

// Inline corpus summary response.
message CorpusSummarizeResponse {
  // Stable corpus summary fields shared with CLI, REST, Rust, and Python.
  CorpusSummary summary = 1;

  // Opt-in corpus summary with embedded evidence provenance.
  CorpusSummaryV2 summary_v2 = 2;
}

// Inline corpus fingerprint request.
message CorpusFingerprintRequest {
  // Inline HL7 messages to fingerprint. The service does not read filesystem
  // paths from this request.
  repeated CorpusMessageInput messages = 1;

  // Optional inline HL7v2 profile YAML content for validation issue-code counts.
  optional string profile = 2;

  // Optional corpus fingerprint evidence schema version.
  //
  // Omitted or 1 preserves the default fingerprint fields. 2 includes the
  // fingerprint_v2 field with embedded provenance.
  int32 fingerprint_schema_version = 3;
}

// Inline corpus fingerprint response.
message CorpusFingerprintResponse {
  // Stable corpus fingerprint fields shared with CLI, REST, Rust, and Python.
  CorpusFingerprint fingerprint = 1;

  // Opt-in corpus fingerprint with embedded evidence provenance.
  CorpusFingerprintV2 fingerprint_v2 = 2;
}

// Inline corpus diff request.
message CorpusDiffRequest {
  // Inline before-corpus messages. The service does not read filesystem paths
  // from this request.
  repeated CorpusMessageInput before = 1;

  // Inline after-corpus messages. The service does not read filesystem paths
  // from this request.
  repeated CorpusMessageInput after = 2;

  // Optional inline HL7v2 profile YAML content for validation issue-code deltas.
  optional string profile = 3;

  // Optional corpus diff evidence schema version.
  //
  // Omitted or 1 preserves the default diff fields. 2 includes the diff_v2
  // field with embedded provenance.
  int32 diff_schema_version = 4;
}

// Inline corpus diff response.
message CorpusDiffResponse {
  // Stable corpus diff fields shared with CLI, REST, Rust, and Python.
  CorpusDiffReport diff = 1;

  // Opt-in corpus diff with embedded evidence provenance.
  CorpusDiffReportV2 diff_v2 = 2;
}

// Stable corpus summary artifact.
message CorpusSummary {
  // Caller-independent corpus root label.
  string root = 1;

  // Number of inline messages inspected.
  uint32 file_count = 2;

  // Number of messages parsed successfully.
  uint32 message_count = 3;

  // Number of messages that could not be parsed as HL7 v2.
  uint32 parse_error_count = 4;

  // Total input bytes across the inline corpus.
  uint64 total_bytes = 5;

  // Message type counts from parsed MSH-9 values.
  repeated CorpusCount message_types = 6;

  // Segment ID counts across parsed messages.
  repeated CorpusCount segments = 7;

  // Field presence counts across parsed messages.
  repeated CorpusFieldPresence field_presence = 8;

  // Per-message parse failures.
  repeated CorpusParseFailure parse_errors = 9;
}

// Corpus summary v2 artifact with embedded evidence provenance.
message CorpusSummaryV2 {
  // Evidence artifact schema version.
  string schema_version = 1;

  // Producer surface that generated this summary.
  string tool_name = 2;

  // Semantic version of the producing crate or binding package.
  string tool_version = 3;

  // Caller-independent corpus root label.
  string root = 4;

  // Number of inline messages inspected.
  uint32 file_count = 5;

  // Number of messages parsed successfully.
  uint32 message_count = 6;

  // Number of messages that could not be parsed as HL7 v2.
  uint32 parse_error_count = 7;

  // Total input bytes across the inline corpus.
  uint64 total_bytes = 8;

  // Message type counts from parsed MSH-9 values.
  repeated CorpusCount message_types = 9;

  // Segment ID counts across parsed messages.
  repeated CorpusCount segments = 10;

  // Field presence counts across parsed messages.
  repeated CorpusFieldPresence field_presence = 11;

  // Per-message parse failures.
  repeated CorpusParseFailure parse_errors = 12;
}

// Stable corpus fingerprint artifact.
message CorpusFingerprint {
  // Corpus fingerprint contract version.
  string fingerprint_version = 1;

  // Producer package version.
  string tool_version = 2;

  // Caller-independent corpus root label.
  string root = 3;

  // Optional profile metadata used for validation issue-code counts.
  CorpusFingerprintProfile profile = 4;

  // Number of inline messages inspected.
  uint32 file_count = 5;

  // Number of messages parsed successfully.
  uint32 message_count = 6;

  // Number of messages that could not be parsed as HL7 v2.
  uint32 parse_error_count = 7;

  // Message type counts from parsed MSH-9 values.
  repeated CorpusCount message_type_counts = 8;

  // Segment ID counts across parsed messages.
  repeated CorpusCount segment_counts = 9;

  // Field presence counts across parsed messages.
  repeated CorpusFieldPresence field_presence = 10;

  // Field cardinality observations across parsed messages.
  repeated CorpusFieldCardinality field_cardinality = 11;

  // Value shape observations across parsed messages.
  repeated CorpusValueShapeStats value_shape_stats = 12;

  // Validation issue-code counts when a profile is supplied.
  repeated CorpusCount validation_issue_code_counts = 13;
}

// Corpus fingerprint v2 artifact with embedded evidence provenance.
message CorpusFingerprintV2 {
  // Evidence artifact schema version.
  string schema_version = 1;

  // Producer surface that generated this fingerprint.
  string tool_name = 2;

  // Corpus fingerprint contract version.
  string fingerprint_version = 3;

  // Producer package version.
  string tool_version = 4;

  // Caller-independent corpus root label.
  string root = 5;

  // Optional profile metadata used for validation issue-code counts.
  CorpusFingerprintProfile profile = 6;

  // Number of inline messages inspected.
  uint32 file_count = 7;

  // Number of messages parsed successfully.
  uint32 message_count = 8;

  // Number of messages that could not be parsed as HL7 v2.
  uint32 parse_error_count = 9;

  // Message type counts from parsed MSH-9 values.
  repeated CorpusCount message_type_counts = 10;

  // Segment ID counts across parsed messages.
  repeated CorpusCount segment_counts = 11;

  // Field presence counts across parsed messages.
  repeated CorpusFieldPresence field_presence = 12;

  // Field cardinality observations across parsed messages.
  repeated CorpusFieldCardinality field_cardinality = 13;

  // Value shape observations across parsed messages.
  repeated CorpusValueShapeStats value_shape_stats = 14;

  // Validation issue-code counts when a profile is supplied.
  repeated CorpusCount validation_issue_code_counts = 15;
}

// Stable corpus diff artifact.
message CorpusDiffReport {
  // Corpus diff contract version.
  string diff_version = 1;

  // Producer package version.
  string tool_version = 2;

  // Caller-independent before-corpus root label.
  string before_root = 3;

  // Caller-independent after-corpus root label.
  string after_root = 4;

  // Optional profile metadata used for validation issue-code deltas.
  CorpusFingerprintProfile profile = 5;

  // File/message input count before/after/delta.
  CorpusTotalDiff file_count = 6;

  // Parsed message count before/after/delta.
  CorpusTotalDiff message_count = 7;

  // Parse error count before/after/delta.
  CorpusTotalDiff parse_error_count = 8;

  // Message types present only in the after corpus.
  repeated string new_message_types = 9;

  // Message types present only in the before corpus.
  repeated string removed_message_types = 10;

  // Segment IDs present only in the after corpus.
  repeated string new_segments = 11;

  // Segment IDs present only in the before corpus.
  repeated string removed_segments = 12;

  // Message type count differences.
  repeated CorpusCountDiff message_type_counts = 13;

  // Segment count differences.
  repeated CorpusCountDiff segment_counts = 14;

  // Field presence differences.
  repeated CorpusFieldPresenceDiff field_presence = 15;

  // Field cardinality differences.
  repeated CorpusFieldCardinalityDiff field_cardinality = 16;

  // Value shape differences.
  repeated CorpusValueShapeStatsDiff value_shape_stats = 17;

  // Validation issue-code count differences when a profile is supplied.
  repeated CorpusCountDiff validation_issue_code_counts = 18;
}

// Corpus diff v2 artifact with embedded evidence provenance.
message CorpusDiffReportV2 {
  // Evidence artifact schema version.
  string schema_version = 1;

  // Producer surface that generated this diff.
  string tool_name = 2;

  // Corpus diff contract version.
  string diff_version = 3;

  // Producer package version.
  string tool_version = 4;

  // Caller-independent before-corpus root label.
  string before_root = 5;

  // Caller-independent after-corpus root label.
  string after_root = 6;

  // Optional profile metadata used for validation issue-code deltas.
  CorpusFingerprintProfile profile = 7;

  // File/message input count before/after/delta.
  CorpusTotalDiff file_count = 8;

  // Parsed message count before/after/delta.
  CorpusTotalDiff message_count = 9;

  // Parse error count before/after/delta.
  CorpusTotalDiff parse_error_count = 10;

  // Message types present only in the after corpus.
  repeated string new_message_types = 11;

  // Message types present only in the before corpus.
  repeated string removed_message_types = 12;

  // Segment IDs present only in the after corpus.
  repeated string new_segments = 13;

  // Segment IDs present only in the before corpus.
  repeated string removed_segments = 14;

  // Message type count differences.
  repeated CorpusCountDiff message_type_counts = 15;

  // Segment count differences.
  repeated CorpusCountDiff segment_counts = 16;

  // Field presence differences.
  repeated CorpusFieldPresenceDiff field_presence = 17;

  // Field cardinality differences.
  repeated CorpusFieldCardinalityDiff field_cardinality = 18;

  // Value shape differences.
  repeated CorpusValueShapeStatsDiff value_shape_stats = 19;

  // Validation issue-code count differences when a profile is supplied.
  repeated CorpusCountDiff validation_issue_code_counts = 20;
}

// Profile metadata attached to a corpus fingerprint.
message CorpusFingerprintProfile {
  // Profile source label. For inline gRPC profiles this is "<inline-profile>".
  string path = 1;

  // SHA-256 hash of the profile content.
  string sha256 = 2;

  // Loaded profile version.
  string version = 3;

  // Loaded profile message structure.
  string message_structure = 4;
}

// Field cardinality observed across parsed corpus messages.
message CorpusFieldCardinality {
  // HL7 path, such as PID.3.
  string path = 1;

  // Minimum occurrences observed in any parsed message.
  uint32 min_per_message = 2;

  // Maximum occurrences observed in any parsed message.
  uint32 max_per_message = 3;

  // Total occurrences across all parsed messages.
  uint32 total_occurrences = 4;

  // Number of parsed messages where this path was present.
  uint32 message_count = 5;
}

// Value shape counts for one HL7 field path.
message CorpusValueShapeStats {
  // HL7 path, such as OBX.5.
  string path = 1;

  // Count of coded/component values.
  uint32 coded_count = 2;

  // Count of timestamp-like values.
  uint32 timestamp_count = 3;

  // Count of numeric values.
  uint32 numeric_count = 4;

  // Count of explicit HL7 null values.
  uint32 null_count = 5;

  // Count of other non-empty text values.
  uint32 text_count = 6;
}

// Total before/after/delta count.
message CorpusTotalDiff {
  // Count observed in the before corpus.
  uint64 before = 1;

  // Count observed in the after corpus.
  uint64 after = 2;

  // after - before as a signed delta.
  int64 delta = 3;
}

// Dimension before/after/delta count.
message CorpusCountDiff {
  // Dimension value, such as a message type or segment ID.
  string value = 1;

  // Count observed in the before corpus.
  uint64 before = 2;

  // Count observed in the after corpus.
  uint64 after = 3;

  // after - before as a signed delta.
  int64 delta = 4;
}

// Field-presence before/after/delta observation.
message CorpusFieldPresenceDiff {
  // HL7 path, such as PID.3.
  string path = 1;

  // Number of before-corpus messages where this path appeared.
  uint64 before_message_count = 2;

  // Number of after-corpus messages where this path appeared.
  uint64 after_message_count = 3;

  // after_message_count - before_message_count.
  int64 message_count_delta = 4;

  // Number of before-corpus field occurrences.
  uint64 before_occurrence_count = 5;

  // Number of after-corpus field occurrences.
  uint64 after_occurrence_count = 6;

  // after_occurrence_count - before_occurrence_count.
  int64 occurrence_count_delta = 7;
}

// Field-cardinality before/after/delta observation.
message CorpusFieldCardinalityDiff {
  // HL7 path, such as PID.3.
  string path = 1;

  // Minimum occurrences per message in the before corpus.
  uint64 before_min_per_message = 2;

  // Minimum occurrences per message in the after corpus.
  uint64 after_min_per_message = 3;

  // after_min_per_message - before_min_per_message.
  int64 min_per_message_delta = 4;

  // Maximum occurrences per message in the before corpus.
  uint64 before_max_per_message = 5;

  // Maximum occurrences per message in the after corpus.
  uint64 after_max_per_message = 6;

  // after_max_per_message - before_max_per_message.
  int64 max_per_message_delta = 7;

  // Total occurrences in the before corpus.
  uint64 before_total_occurrences = 8;

  // Total occurrences in the after corpus.
  uint64 after_total_occurrences = 9;

  // after_total_occurrences - before_total_occurrences.
  int64 total_occurrences_delta = 10;

  // Number of before-corpus messages where this path appeared.
  uint64 before_message_count = 11;

  // Number of after-corpus messages where this path appeared.
  uint64 after_message_count = 12;

  // after_message_count - before_message_count.
  int64 message_count_delta = 13;
}

// Value-shape before/after/delta observation.
message CorpusValueShapeStatsDiff {
  // HL7 path, such as OBX.5.
  string path = 1;

  // Coded/component value count before/after/delta.
  CorpusTotalDiff coded_count = 2;

  // Timestamp-like value count before/after/delta.
  CorpusTotalDiff timestamp_count = 3;

  // Numeric value count before/after/delta.
  CorpusTotalDiff numeric_count = 4;

  // Explicit HL7 null value count before/after/delta.
  CorpusTotalDiff null_count = 5;

  // Other non-empty text count before/after/delta.
  CorpusTotalDiff text_count = 6;
}

// Count for a corpus dimension.
message CorpusCount {
  // Dimension value, such as a message type or segment ID.
  string value = 1;

  // Number of occurrences.
  uint32 count = 2;
}

// Field presence count across an inline corpus.
message CorpusFieldPresence {
  // HL7 path, such as PID.3.
  string path = 1;

  // Number of parsed messages where this path appeared.
  uint32 message_count = 2;

  // Number of field occurrences across all parsed messages.
  uint32 occurrence_count = 3;
}

// Parse failure captured while summarizing an inline corpus.
message CorpusParseFailure {
  // Caller-supplied message label or generated inline message label.
  string path = 1;

  // Parser error string. This must not include raw message content.
  string error = 2;
}

// Validation Issue
message ValidationIssue {
  enum Severity {
    SEVERITY_UNSPECIFIED = 0;
    SEVERITY_ERROR = 1;
    SEVERITY_WARNING = 2;
    SEVERITY_INFO = 3;
  }

  // Error code
  string code = 1;

  // Human-readable message
  string message = 2;

  // Severity
  Severity severity = 3;

  // Location in message
  Location location = 4;

  // Remediation advice
  string advice = 5;
}

// Location in message
message Location {
  // Segment ID
  string segment = 1;

  // Field number
  int32 field = 2;

  // Component number
  int32 component = 3;

  // Repetition number
  int32 repetition = 4;

  // Byte offset
  int64 byte_offset = 5;
}

// Validation Summary
message ValidationSummary {
  int32 error_count = 1;
  int32 warning_count = 2;
  int32 info_count = 3;
}

// Stable validation report artifact.
message ValidationReport {
  // Whether validation passed without error-level issues
  bool valid = 1;

  // HL7 trigger event from MSH.9, such as ADT^A01
  string message_type = 2;

  // Profile identifier, usually the loaded profile message structure
  optional string profile = 3;

  // Number of parsed message segments
  int32 segment_count = 4;

  // Number of reported validation issues
  int32 issue_count = 5;

  // Stable validation issue records
  repeated ValidationReportIssue issues = 6;
}

// Validation report v2 artifact with embedded evidence provenance.
message ValidationReportV2 {
  // Evidence artifact schema version
  string schema_version = 1;

  // Producer surface that generated this report
  string tool_name = 2;

  // Semantic version of the producing crate or binding package
  string tool_version = 3;

  // Whether validation passed without error-level issues
  bool valid = 4;

  // HL7 trigger event from MSH.9, such as ADT^A01
  string message_type = 5;

  // Profile identifier, usually the loaded profile message structure
  optional string profile = 6;

  // Reproducible profile identity metadata when available
  ValidationReportProfileIdentity profile_identity = 7;

  // Number of parsed message segments
  int32 segment_count = 8;

  // Number of reported validation issues
  int32 issue_count = 9;

  // Stable validation issue records
  repeated ValidationReportIssue issues = 10;
}

// Reproducible profile identity metadata.
message ValidationReportProfileIdentity {
  // Display label for the profile source
  string label = 1;

  // Loaded profile message structure when known
  optional string message_structure = 2;

  // Loaded profile HL7 version when known
  optional string version = 3;

  // SHA-256 digest of the profile bytes when available
  optional string sha256 = 4;
}

// Stable validation issue record used in machine-readable reports.
message ValidationReportIssue {
  // Stable snake_case issue code
  string code = 1;

  // Error or warning severity
  string severity = 2;

  // HL7 path associated with the issue, such as PID.3
  optional string path = 3;

  // Stable rule identifier
  optional string rule_id = 4;

  // Human-readable issue message
  string message = 5;

  // Zero-based segment index when known
  optional uint32 segment_index = 6;

  // One-based HL7 field index when known
  optional uint32 field_index = 7;
}

// ACK Request
message GenerateAckRequest {
  // Original message
  bytes message = 1;

  // ACK code
  enum AckCode {
    ACK_CODE_UNSPECIFIED = 0;
    ACK_CODE_AA = 1;  // Application Accept
    ACK_CODE_AE = 2;  // Application Error
    ACK_CODE_AR = 3;  // Application Reject
  }

  AckCode code = 2;

  // Error message (for AE/AR)
  optional string error_message = 3;
}

// ACK Response
message GenerateAckResponse {
  // Generated ACK message
  bytes ack_message = 1;

  // Parsed ACK (for verification)
  Message parsed_ack = 2;
}

// Normalize Request
message NormalizeRequest {
  // Message to normalize
  bytes message = 1;

  // Normalization options
  NormalizeOptions options = 2;
}

message NormalizeOptions {
  // Use canonical delimiters
  bool canonical_delimiters = 1;

  // Add MLLP framing
  bool mllp_frame = 2;

  // Sort fields
  bool sort_fields = 3;
}

// Normalize Response
message NormalizeResponse {
  // Normalized message
  bytes normalized = 1;
}

// Health Check Request
message HealthCheckRequest {}

// Health Check Response
message HealthCheckResponse {
  enum ServingStatus {
    SERVING_STATUS_UNSPECIFIED = 0;
    SERVING_STATUS_SERVING = 1;
    SERVING_STATUS_NOT_SERVING = 2;
    SERVING_STATUS_SERVICE_UNKNOWN = 3;
  }

  ServingStatus status = 1;
  string version = 2;
  int64 uptime_seconds = 3;
}

// Error
message Error {
  // Error code
  string code = 1;

  // Error message
  string message = 2;

  // Additional details
  map<string, string> details = 3;

  // Trace ID
  string trace_id = 4;
}
