messagefoundry 0.2.8__tar.gz → 0.2.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (803) hide show
  1. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/ci.yml +31 -5
  2. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/CHANGELOG.md +57 -0
  3. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/PKG-INFO +1 -1
  4. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CONFIGURATION.md +45 -2
  5. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CONNECTIONS.md +86 -1
  6. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0017-consumer-deployment-model.md +39 -0
  7. messagefoundry-0.2.9/docs/adr/0027-per-connection-retention.md +208 -0
  8. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0041-load-path-attestation-and-change-attribution.md +36 -7
  9. messagefoundry-0.2.9/docs/adr/0042-embedded-document-pruning.md +177 -0
  10. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/README.md +3 -2
  11. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/TUNING-BASELINE.md +43 -0
  12. messagefoundry-0.2.9/docs/releases/MULTISESSION-PLAN-4.md +167 -0
  13. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/ASVS-L2-PHASE0-CHANGES.md +1 -0
  14. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/__init__.py +3 -1
  15. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/__main__.py +3 -0
  16. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/app.py +170 -24
  17. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/models.py +14 -0
  18. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/connections_file.py +25 -1
  19. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/models.py +15 -0
  20. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/settings.py +60 -4
  21. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/wiring.py +98 -5
  22. messagefoundry-0.2.9/messagefoundry/integrity.py +351 -0
  23. messagefoundry-0.2.9/messagefoundry/parsing/binary.py +312 -0
  24. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/alert_sinks.py +29 -3
  25. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/alerts.py +34 -0
  26. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/engine.py +13 -0
  27. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/retention.py +165 -10
  28. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/wiring_runner.py +43 -0
  29. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/__init__.py +2 -0
  30. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/base.py +44 -2
  31. messagefoundry-0.2.9/messagefoundry/store/document_strip.py +51 -0
  32. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/postgres.py +158 -23
  33. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/sqlserver.py +111 -9
  34. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/store.py +186 -18
  35. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/mllp.py +17 -4
  36. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/tcp.py +12 -3
  37. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/x12.py +12 -3
  38. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/security/crypto_inventory_check.py +4 -0
  39. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_alert_rules.py +44 -0
  40. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_alert_sinks.py +27 -0
  41. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_api.py +37 -0
  42. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_config_source_trust.py +10 -0
  43. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connection_event_emit.py +25 -8
  44. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connections_file.py +134 -0
  45. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_delivery_settings.py +38 -1
  46. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dependabot_automerge_guardrails.py +7 -0
  47. messagefoundry-0.2.9/tests/test_dual_control_reload.py +190 -0
  48. messagefoundry-0.2.9/tests/test_embedded_document_pruning.py +367 -0
  49. messagefoundry-0.2.9/tests/test_per_connection_retention.py +373 -0
  50. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_settings.py +38 -0
  51. messagefoundry-0.2.9/tests/test_startup_attestation.py +254 -0
  52. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_wiring_engine.py +103 -0
  53. messagefoundry-0.2.8/messagefoundry/parsing/binary.py +0 -152
  54. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.claude/settings.json +0 -0
  55. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.dockerignore +0 -0
  56. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.gitattributes +0 -0
  57. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/CODEOWNERS +0 -0
  58. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  59. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  60. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  61. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  62. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/SECURITY.md +0 -0
  63. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/dependabot.yml +0 -0
  64. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/benchmark.yml +0 -0
  65. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/cla.yml +0 -0
  66. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/codeql.yml +0 -0
  67. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/dependabot-auto-merge.yml +0 -0
  68. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/dependabot-lock-resync.yml +0 -0
  69. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/freethread-smoke.yml +0 -0
  70. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/release-sync-check.yml +0 -0
  71. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/release.yml +0 -0
  72. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/scorecard.yml +0 -0
  73. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/security.yml +0 -0
  74. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/workflows/vuln-metrics.yml +0 -0
  75. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.github/zizmor.yml +0 -0
  76. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.gitignore +0 -0
  77. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.gitleaks.toml +0 -0
  78. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.mefor-hooks/pre-commit +0 -0
  79. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.pre-commit-config.yaml +0 -0
  80. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/.semgrep/messagefoundry.yml +0 -0
  81. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/CLA.md +0 -0
  82. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/CLAUDE.md +0 -0
  83. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/CODE_OF_CONDUCT.md +0 -0
  84. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/COMMERCIAL-LICENSE.md +0 -0
  85. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/CONTRIBUTING.md +0 -0
  86. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/GOVERNANCE.md +0 -0
  87. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/LICENSE +0 -0
  88. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/MAINTAINERS.md +0 -0
  89. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/NOTICE +0 -0
  90. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/README.md +0 -0
  91. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/Dockerfile +0 -0
  92. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/README.md +0 -0
  93. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/compose.yaml +0 -0
  94. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/k8s/secret.example.yaml +0 -0
  95. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/k8s/statefulset.yaml +0 -0
  96. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/locks/requirements-core.lock +0 -0
  97. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/locks/requirements-sqlserver.lock +0 -0
  98. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/secrets.env.example +0 -0
  99. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/smoke/Dockerfile +0 -0
  100. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/smoke/config/IB_Test_ADT.py +0 -0
  101. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docker/smoke/send_adt.py +0 -0
  102. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/ADOPTER-CI.md +0 -0
  103. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/AI.md +0 -0
  104. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/ARCHITECTURE.md +0 -0
  105. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/BACKLOG.md +0 -0
  106. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CI-QUALITY.md +0 -0
  107. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CLUSTERING.md +0 -0
  108. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CODESETS.md +0 -0
  109. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CONTAINER-EXPOSURE-EVALUATION.md +0 -0
  110. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CONTRIBUTOR-FIRST-ISSUES.md +0 -0
  111. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/CONTRIBUTOR-PROGRAM-PLAN.md +0 -0
  112. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/COUNSEL-ENGAGEMENT-BRIEF.md +0 -0
  113. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/DEPLOY-SERVER-DB.md +0 -0
  114. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/DEPLOYMENT.md +0 -0
  115. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/DICOM.md +0 -0
  116. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/DUAL_LICENSING_PLAN.md +0 -0
  117. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/EARLY-ADOPTER-GUIDE.md +0 -0
  118. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/FEATURE-MAP.md +0 -0
  119. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/HL7-VALIDATION.md +0 -0
  120. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/INSTALL-GUIDE.md +0 -0
  121. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/LOAD-TESTING.md +0 -0
  122. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/MENTAL-MODEL.md +0 -0
  123. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/MessageFoundry-Mental-Model.docx +0 -0
  124. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/PHI.md +0 -0
  125. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/REMOTE-CONSOLE-CUSTOMER-GUIDE.md +0 -0
  126. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/REMOTE-CONSOLE.md +0 -0
  127. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/SECURITY-REMEDIATION-LEDGER.md +0 -0
  128. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/SECURITY.md +0 -0
  129. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/SERVICE.md +0 -0
  130. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/SUPPORT-POLICY.md +0 -0
  131. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/SYSTEM-REQUIREMENTS.md +0 -0
  132. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/Secure_AI_Development_Standards.md +0 -0
  133. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/Secure_Development_Standards.md +0 -0
  134. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/TEE-RELAY.md +0 -0
  135. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/THROUGHPUT-IMPROVEMENTS.md +0 -0
  136. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/USER-GUIDE.md +0 -0
  137. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/WORKTREES.md +0 -0
  138. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0001-staged-pipeline-architecture.md +0 -0
  139. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0002-phase2-transport-security-and-strong-auth.md +0 -0
  140. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0003-non-hl7-transports-database-rest-soap.md +0 -0
  141. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0004-payload-agnostic-ingress.md +0 -0
  142. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0005-transform-accessible-state.md +0 -0
  143. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0006-external-data-lookups.md +0 -0
  144. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0007-gui-manageable-connections-toml.md +0 -0
  145. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0008-cluster-observability-api.md +0 -0
  146. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0009-run-scoped-context-providers.md +0 -0
  147. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0010-handler-callable-db-lookup.md +0 -0
  148. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0011-timer-scheduled-source.md +0 -0
  149. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0012-x12-edi-codec.md +0 -0
  150. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0013-increment-2-reingress-design.md +0 -0
  151. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0013-query-response-orchestration.md +0 -0
  152. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0014-alerting-rules-engine.md +0 -0
  153. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0015-ws-soap-outbound-mtls-wssecurity.md +0 -0
  154. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0016-synchronous-x12-request-response.md +0 -0
  155. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0018-per-message-signatures-accepted-risk.md +0 -0
  156. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0019-pluggable-keyprovider-hsm-kms-vault.md +0 -0
  157. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0020-protocol-diagnostic-capture.md +0 -0
  158. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0021-inbound-ack-nak-capture-response-sent.md +0 -0
  159. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0022-fhir-resource-codec-rest-client.md +0 -0
  160. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0024-smart-backend-services-token-provider.md +0 -0
  161. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0025-dicom-codec-store-connectors.md +0 -0
  162. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0026-off-box-egress-update-check.md +0 -0
  163. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0028-base64-binary-carriage-codec.md +0 -0
  164. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0030-anonymization-test-harness-tee.md +0 -0
  165. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0031-startup-connection-fault-isolation.md +0 -0
  166. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0032-console-desktop-launch.md +0 -0
  167. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0033-gui-manageable-code-sets.md +0 -0
  168. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0034-static-analysis-triage-policy-accepted-risk-register.md +0 -0
  169. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0035-ide-extension-workspace-trust-and-scope.md +0 -0
  170. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0036-windows-config-source-trust.md +0 -0
  171. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0037-multi-process-sharding-l3.md +0 -0
  172. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0038-internal-pass-through-connector.md +0 -0
  173. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0039-database-tier-sharding-l5.md +0 -0
  174. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/0040-free-threaded-engine-support.md +0 -0
  175. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/adr/TEMPLATE.md +0 -0
  176. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-components.png +0 -0
  177. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-components.svg +0 -0
  178. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-config-graph.png +0 -0
  179. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-config-graph.svg +0 -0
  180. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-diagram.md +0 -0
  181. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-message-flow.png +0 -0
  182. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-message-flow.svg +0 -0
  183. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-topology.png +0 -0
  184. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/architecture-topology.svg +0 -0
  185. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/results/2026-06-16-ci-linux/environment.txt +0 -0
  186. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/results/2026-06-16-ci-linux/failover-postgres.json +0 -0
  187. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/results/2026-06-16-ci-linux/failover-sqlserver.json +0 -0
  188. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/results/2026-06-16-ci-linux/reference-postgres.json +0 -0
  189. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/results/2026-06-16-ci-linux/reference-sqlite.json +0 -0
  190. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/results/2026-06-16-ci-linux/reference-sqlserver.json +0 -0
  191. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/benchmarks/step-b-write-amplification.md +0 -0
  192. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/design/dbshard.md +0 -0
  193. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/design/freethread.md +0 -0
  194. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/design/multiproc.md +0 -0
  195. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/hl7-message-ordering-reference.md +0 -0
  196. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/message-ordering-design.md +0 -0
  197. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/ASVS-OPTION-A-MULTISESSION-PLAN.md +0 -0
  198. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/ASVS-PARTIALS-SWEEP-MULTISESSION-PLAN.md +0 -0
  199. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/DOGFOOD-BACKLOG-MULTISESSION-PLAN.md +0 -0
  200. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/MULTISESSION-PLAN-3.md +0 -0
  201. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/MULTISESSION-PLAN-v0.2.md +0 -0
  202. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/MULTISESSION-PLAN.md +0 -0
  203. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/PLAN-3-LANE-HANDOFFS.md +0 -0
  204. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/V0.2-LANE-HANDOFFS.md +0 -0
  205. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/v0.1-EXECUTION-PLAN.md +0 -0
  206. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/v0.1-PLAN.md +0 -0
  207. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/releases/v0.1.0-PRETAG-CHECKLIST.md +0 -0
  208. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/research/cloud-deployment-research-2026-06.md +0 -0
  209. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/research/config-ux-review.md +0 -0
  210. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/research/non-hl7-transform-components.md +0 -0
  211. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/reviews/DEPENDENCY-INFOSEC-POSTURE-2026-06-23.md +0 -0
  212. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/reviews/FULL-REVIEW-2026-06-10.md +0 -0
  213. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/ADVISORY-PROCESS.md +0 -0
  214. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/ASVS-FAILS-REMEDIATION-PLAN.md +0 -0
  215. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/ASVS-L2-REMEDIATION-PLAN.md +0 -0
  216. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/ASVS-L3-ASSESSMENT.md +0 -0
  217. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/ASVS-L3-REMEDIATION-PLAN.md +0 -0
  218. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/ASVS-L3-STATUS.md +0 -0
  219. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/BEYOND-ASVS-L3-ONEPAGE.md +0 -0
  220. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/BEYOND-ASVS-L3-REMEDIATION-PLAN-ONEPAGE.md +0 -0
  221. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/BEYOND-ASVS-L3-REMEDIATION-PLAN.md +0 -0
  222. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/BEYOND-ASVS-L3.md +0 -0
  223. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/DEP-CVE-RUNBOOK.md +0 -0
  224. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/DEPENDENCY-METRICS.md +0 -0
  225. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/MEFOR-Code-Review-Checklist.xlsx +0 -0
  226. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/PHASE-8C-RBAC.md +0 -0
  227. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/PUBLISHING.md +0 -0
  228. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/RCA-TEMPLATE.md +0 -0
  229. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/RELEASE-GATE.md +0 -0
  230. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/REMEDIATION-PLAN.md +0 -0
  231. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/REVIEW-2026-06-07.md +0 -0
  232. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/SDS-CONFORMANCE-REVIEW-2026-06-12.md +0 -0
  233. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/SDS-REMEDIATION-PLAN.md +0 -0
  234. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/SECURITY-POSTURE.md +0 -0
  235. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/SOUP-DEPENDENCY-HANDLING.md +0 -0
  236. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/SOUP-REVIEW-2026-06-18.md +0 -0
  237. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/SOUP-REVIEW-PROCEDURE.md +0 -0
  238. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/security/THREAT-MODEL.md +0 -0
  239. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/testing/VERIFY.md +0 -0
  240. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/testing/WIN2025-ACCEPTANCE.md +0 -0
  241. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/testing/WIN2025-TEST-MATRIX.md +0 -0
  242. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/docs/testing/WIN2025-TEST-PLAN.md +0 -0
  243. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/environments/dev.toml +0 -0
  244. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/environments/prod.toml +0 -0
  245. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/README.md +0 -0
  246. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/__main__.py +0 -0
  247. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/acceptance/__init__.py +0 -0
  248. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/acceptance/__main__.py +0 -0
  249. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/acceptance/matrix.py +0 -0
  250. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/acceptance/probes.py +0 -0
  251. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/acceptance/report.py +0 -0
  252. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/acceptance/runner.py +0 -0
  253. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/compose.py +0 -0
  254. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/config/coverage.py +0 -0
  255. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/config/load/_shape.py +0 -0
  256. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/config/load/graph.py +0 -0
  257. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/config/passthrough/graph.py +0 -0
  258. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/config/store_once/graph.py +0 -0
  259. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/file_panel.py +0 -0
  260. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/file_transport.py +0 -0
  261. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/__init__.py +0 -0
  262. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/corpus.py +0 -0
  263. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/correlator.py +0 -0
  264. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/enginepoll.py +0 -0
  265. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/failover.py +0 -0
  266. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/failover_track.py +0 -0
  267. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/governor.py +0 -0
  268. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/ids.py +0 -0
  269. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/metrics.py +0 -0
  270. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profile.py +0 -0
  271. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/README.md +0 -0
  272. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/adt-fanout-stress.toml +0 -0
  273. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/closed-loop.toml +0 -0
  274. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/failover.toml +0 -0
  275. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/fanout-baseline.toml +0 -0
  276. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/malformed-load.toml +0 -0
  277. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/reference.toml +0 -0
  278. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/smoke-sqlserver.toml +0 -0
  279. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/smoke.toml +0 -0
  280. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/soak.toml +0 -0
  281. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/spike-burst.toml +0 -0
  282. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/sustained-overload.toml +0 -0
  283. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/profiles/writeamp.toml +0 -0
  284. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/report.py +0 -0
  285. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/runner.py +0 -0
  286. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/sender.py +0 -0
  287. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/load/sink.py +0 -0
  288. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/mllp.py +0 -0
  289. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/monitor.py +0 -0
  290. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/receive.py +0 -0
  291. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/reconcile/__init__.py +0 -0
  292. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/reconcile/__main__.py +0 -0
  293. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/reconcile/capture.py +0 -0
  294. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/reconcile/compare.py +0 -0
  295. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/reconcile/normalize.py +0 -0
  296. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/reconcile/report.py +0 -0
  297. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/scenarios.py +0 -0
  298. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/send.py +0 -0
  299. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/harness/window.py +0 -0
  300. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/.gitignore +0 -0
  301. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/.vscodeignore +0 -0
  302. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/README.md +0 -0
  303. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/esbuild.js +0 -0
  304. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/media/hl7schema.json +0 -0
  305. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/media/icon-amber.svg +0 -0
  306. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/media/icon.png +0 -0
  307. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/media/icon.svg +0 -0
  308. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/package-lock.json +0 -0
  309. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/package.json +0 -0
  310. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/snippets/messagefoundry.code-snippets +0 -0
  311. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/aiPolicy.ts +0 -0
  312. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/alertEditor.ts +0 -0
  313. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/auth.ts +0 -0
  314. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/chat.ts +0 -0
  315. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/cli.ts +0 -0
  316. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/codeSetEditor.ts +0 -0
  317. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/codesetsTree.ts +0 -0
  318. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/completion.ts +0 -0
  319. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/connectionEditor.ts +0 -0
  320. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/editorToolbar.ts +0 -0
  321. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/engineClient.ts +0 -0
  322. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/engineTarget.ts +0 -0
  323. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/extension.ts +0 -0
  324. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/generate.ts +0 -0
  325. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/git.ts +0 -0
  326. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/graphTree.ts +0 -0
  327. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/home.ts +0 -0
  328. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/insertElement.ts +0 -0
  329. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/newRoute.ts +0 -0
  330. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/promote.ts +0 -0
  331. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/promoteTarget.ts +0 -0
  332. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/sourceControl.ts +0 -0
  333. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/runTest.ts +0 -0
  334. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/ai-policy.test.ts +0 -0
  335. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/chat.test.ts +0 -0
  336. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/editor-toolbar.test.ts +0 -0
  337. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/engine-target.test.ts +0 -0
  338. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/extension.test.ts +0 -0
  339. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/index.ts +0 -0
  340. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/insert-element.test.ts +0 -0
  341. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/promote-target.test.ts +0 -0
  342. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/pythonpath.test.ts +0 -0
  343. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/test/suite/settings-scope.test.ts +0 -0
  344. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/testBench.ts +0 -0
  345. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/src/validate.ts +0 -0
  346. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/tsconfig.json +0 -0
  347. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/ide/tsconfig.test.json +0 -0
  348. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/mefor.code-workspace +0 -0
  349. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/adr_analyze.py +0 -0
  350. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/anon/__init__.py +0 -0
  351. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/anon/_pools.py +0 -0
  352. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/anon/hl7.py +0 -0
  353. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/anon/keying.py +0 -0
  354. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/anon/leak.py +0 -0
  355. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/anon/rules.py +0 -0
  356. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/anon/surrogates.py +0 -0
  357. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/__init__.py +0 -0
  358. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/approvals.py +0 -0
  359. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/auth_models.py +0 -0
  360. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/auth_routes.py +0 -0
  361. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/field_authz.py +0 -0
  362. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/metrics.py +0 -0
  363. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/security.py +0 -0
  364. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/api/tls.py +0 -0
  365. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/__init__.py +0 -0
  366. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/data/common_passwords.NOTICE +0 -0
  367. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/data/common_passwords.txt +0 -0
  368. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/identity.py +0 -0
  369. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/ldap.py +0 -0
  370. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/notifications.py +0 -0
  371. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/passwords.py +0 -0
  372. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/permissions.py +0 -0
  373. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/policy.py +0 -0
  374. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/ratelimit.py +0 -0
  375. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/service.py +0 -0
  376. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/tokens.py +0 -0
  377. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/auth/totp.py +0 -0
  378. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/checks.py +0 -0
  379. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/__init__.py +0 -0
  380. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/active_environment.py +0 -0
  381. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/ai_policy.py +0 -0
  382. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/alerts_edit.py +0 -0
  383. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/code_sets.py +0 -0
  384. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/codeset_edit.py +0 -0
  385. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/connections_edit.py +0 -0
  386. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/db_lookup.py +0 -0
  387. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/environments.py +0 -0
  388. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/fingerprint.py +0 -0
  389. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/ingest_time.py +0 -0
  390. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/reference.py +0 -0
  391. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/response.py +0 -0
  392. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/run_context.py +0 -0
  393. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/state.py +0 -0
  394. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/config/tls_policy.py +0 -0
  395. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/__init__.py +0 -0
  396. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/__main__.py +0 -0
  397. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/_async.py +0 -0
  398. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/alerts_page.py +0 -0
  399. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/change_password.py +0 -0
  400. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/client.py +0 -0
  401. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/connections.py +0 -0
  402. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/dead_letters_page.py +0 -0
  403. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/delegates.py +0 -0
  404. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/event_log_page.py +0 -0
  405. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/icons/alerts.svg +0 -0
  406. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/icons/connections.svg +0 -0
  407. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/icons/dead-letters.svg +0 -0
  408. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/icons/engine-status.svg +0 -0
  409. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/icons/log-search.svg +0 -0
  410. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/icons/logo-lockup.svg +0 -0
  411. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/icons/users.svg +0 -0
  412. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/login.py +0 -0
  413. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/mfa.py +0 -0
  414. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/reauth.py +0 -0
  415. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/resources/README.md +0 -0
  416. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/resources/app.ico +0 -0
  417. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/resources/app.svg +0 -0
  418. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/search.py +0 -0
  419. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/service_control.py +0 -0
  420. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/sessions.py +0 -0
  421. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/shards.py +0 -0
  422. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/shell.py +0 -0
  423. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/status.py +0 -0
  424. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/theme.py +0 -0
  425. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/users_page.py +0 -0
  426. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/console/widgets.py +0 -0
  427. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/README.md +0 -0
  428. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/__init__.py +0 -0
  429. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/_core.py +0 -0
  430. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/_hl7data.py +0 -0
  431. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/adt.py +0 -0
  432. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/all_types.py +0 -0
  433. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/bar.py +0 -0
  434. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/dft.py +0 -0
  435. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/documents.py +0 -0
  436. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/mdm.py +0 -0
  437. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/mfn.py +0 -0
  438. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/oml.py +0 -0
  439. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/orl.py +0 -0
  440. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/orm.py +0 -0
  441. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/oru.py +0 -0
  442. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/ras.py +0 -0
  443. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/rde.py +0 -0
  444. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/siu.py +0 -0
  445. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/generators/vxu.py +0 -0
  446. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/hl7schema.py +0 -0
  447. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/last_resort.py +0 -0
  448. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/logging_setup.py +0 -0
  449. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/__init__.py +0 -0
  450. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/consistency.py +0 -0
  451. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/dicom/__init__.py +0 -0
  452. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/dicom/_deps.py +0 -0
  453. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/dicom/_util.py +0 -0
  454. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/dicom/dataset.py +0 -0
  455. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/dicom/errors.py +0 -0
  456. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/dicom/hl7_map.py +0 -0
  457. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/dicom/peek.py +0 -0
  458. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/fhir/__init__.py +0 -0
  459. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/fhir/_deps.py +0 -0
  460. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/fhir/errors.py +0 -0
  461. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/fhir/peek.py +0 -0
  462. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/fhir/resource.py +0 -0
  463. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/groups.py +0 -0
  464. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/message.py +0 -0
  465. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/peek.py +0 -0
  466. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/split.py +0 -0
  467. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/summary.py +0 -0
  468. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/tree.py +0 -0
  469. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/validate.py +0 -0
  470. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/x12/__init__.py +0 -0
  471. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/x12/delimiters.py +0 -0
  472. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/x12/errors.py +0 -0
  473. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/x12/interchange.py +0 -0
  474. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/x12/message.py +0 -0
  475. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/parsing/x12/peek.py +0 -0
  476. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/__init__.py +0 -0
  477. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/cert_expiry.py +0 -0
  478. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/cluster.py +0 -0
  479. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/cluster_sqlserver.py +0 -0
  480. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/config_convergence.py +0 -0
  481. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/dryrun.py +0 -0
  482. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/leader_tasks.py +0 -0
  483. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/reference_sync.py +0 -0
  484. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/security_notify.py +0 -0
  485. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/sharding.py +0 -0
  486. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/state_convergence.py +0 -0
  487. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/pipeline/supervisor.py +0 -0
  488. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/py.typed +0 -0
  489. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/redaction.py +0 -0
  490. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/scaffold.py +0 -0
  491. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/secrets_dpapi.py +0 -0
  492. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/audit_tee.py +0 -0
  493. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/crypto.py +0 -0
  494. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/store/keyprovider.py +0 -0
  495. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/timezone.py +0 -0
  496. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/__init__.py +0 -0
  497. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/base.py +0 -0
  498. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/database.py +0 -0
  499. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/dicom.py +0 -0
  500. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/dicomweb.py +0 -0
  501. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/fhir.py +0 -0
  502. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/file.py +0 -0
  503. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/framing.py +0 -0
  504. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/loopback.py +0 -0
  505. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/passthrough.py +0 -0
  506. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/remotefile.py +0 -0
  507. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/rest.py +0 -0
  508. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/signing.py +0 -0
  509. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/smart.py +0 -0
  510. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/soap.py +0 -0
  511. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/transports/timer.py +0 -0
  512. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/verify/__init__.py +0 -0
  513. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/verify/checks.py +0 -0
  514. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/verify/model.py +0 -0
  515. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/verify/report.py +0 -0
  516. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/verify/runner.py +0 -0
  517. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/messagefoundry/verify/smoke.py +0 -0
  518. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/packaging/messagefoundry-harness/README.md +0 -0
  519. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/packaging/messagefoundry-harness/pyproject.toml +0 -0
  520. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/pyproject.toml +0 -0
  521. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/requirements.lock +0 -0
  522. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/IB_ACME_ADT.py +0 -0
  523. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/IB_FHIR_INTAKE.py +0 -0
  524. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/IB_IMMUNIZATION_VXU.py +0 -0
  525. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/IB_PARTNER_X12.py +0 -0
  526. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/IB_RADIOLOGY_SR.py +0 -0
  527. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/IB_RTE_ELIGIBILITY.py +0 -0
  528. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/adt.py +0 -0
  529. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/codesets/event_labels.csv +0 -0
  530. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/codesets/facility_mnemonics.toml +0 -0
  531. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/config/connections.toml +0 -0
  532. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/consistency/validated_adt.py +0 -0
  533. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/dicom/generate_sr_sample.py +0 -0
  534. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/adt_a01.hl7 +0 -0
  535. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/adt_batch.hl7 +0 -0
  536. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/.gitattributes +0 -0
  537. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/README.md +0 -0
  538. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/adt_a01.txt +0 -0
  539. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/adt_a03.txt +0 -0
  540. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/batch_18_messages.txt +0 -0
  541. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/erp_z99_v231.hl7 +0 -0
  542. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/omd_o03.txt +0 -0
  543. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/omd_o03_rep.txt +0 -0
  544. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/hapi-hl7v2/oml_o21.hl7 +0 -0
  545. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/messages/x12_270_eligibility.edi +0 -0
  546. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/results_relay/README.md +0 -0
  547. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/results_relay/codesets/test_codes.csv +0 -0
  548. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/results_relay/messages/oru_all_cancelled.hl7 +0 -0
  549. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/results_relay/messages/oru_results.hl7 +0 -0
  550. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/results_relay/results_relay.py +0 -0
  551. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/samples/send_mllp.py +0 -0
  552. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/console/install-console-shortcut.ps1 +0 -0
  553. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/console/pack_ico.py +0 -0
  554. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/console/uninstall-console-shortcut.ps1 +0 -0
  555. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/dev/postgres.ps1 +0 -0
  556. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/dev/sqlserver-docker.ps1 +0 -0
  557. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/dev/sqlserver.ps1 +0 -0
  558. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/hooks/block-blanket-git-stage.ps1 +0 -0
  559. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/publish/check_release_sync.py +0 -0
  560. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/publish/publish-denylist.txt +0 -0
  561. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/publish/publish.ps1 +0 -0
  562. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/publish/scan_forbidden.py +0 -0
  563. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/security/vuln_metrics.py +0 -0
  564. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/service/import-db-ca.ps1 +0 -0
  565. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/service/install-service.ps1 +0 -0
  566. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/service/uninstall-service.ps1 +0 -0
  567. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/trace_icon.py +0 -0
  568. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/worktree/new.ps1 +0 -0
  569. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/worktree/remove.ps1 +0 -0
  570. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/worktree/session-context.ps1 +0 -0
  571. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/scripts/worktree/spawn.ps1 +0 -0
  572. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/__init__.py +0 -0
  573. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/__main__.py +0 -0
  574. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/__init__.py +0 -0
  575. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/_hl7data.py +0 -0
  576. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/_pools.py +0 -0
  577. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/hl7.py +0 -0
  578. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/keying.py +0 -0
  579. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/leak.py +0 -0
  580. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/rules.py +0 -0
  581. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/anon/surrogates.py +0 -0
  582. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/compare.py +0 -0
  583. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/correlate.py +0 -0
  584. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/hl7_fields.py +0 -0
  585. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/mefor_api.py +0 -0
  586. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/mllp.py +0 -0
  587. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/relay.py +0 -0
  588. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/report.py +0 -0
  589. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tee/store.py +0 -0
  590. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/_dicom_sample.py +0 -0
  591. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/_failover_load_support.py +0 -0
  592. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/_fhir_fixtures.py +0 -0
  593. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/conftest.py +0 -0
  594. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_acceptance_framework.py +0 -0
  595. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ack_capture_runner.py +0 -0
  596. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ack_sent_store.py +0 -0
  597. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_active_environment.py +0 -0
  598. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ad_group_scope.py +0 -0
  599. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_admin_new_ip.py +0 -0
  600. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_adr_analyze.py +0 -0
  601. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ai_policy.py +0 -0
  602. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_alerts_edit.py +0 -0
  603. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_alerts_rules_api.py +0 -0
  604. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_anon_core.py +0 -0
  605. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_anon_integration.py +0 -0
  606. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_anon_parity.py +0 -0
  607. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_api_auth.py +0 -0
  608. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_api_reload.py +0 -0
  609. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_api_tls.py +0 -0
  610. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_approvals.py +0 -0
  611. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_asvs_phase0.py +0 -0
  612. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_audit_integrity.py +0 -0
  613. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_audit_offbox_tee.py +0 -0
  614. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_auth_core.py +0 -0
  615. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_auth_entry_hardening.py +0 -0
  616. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_auth_hardening.py +0 -0
  617. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_auth_service.py +0 -0
  618. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_auth_session_lifecycle.py +0 -0
  619. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_auth_store.py +0 -0
  620. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_binary_carriage.py +0 -0
  621. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_bootstrap_admin_perms.py +0 -0
  622. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_cert_expiry.py +0 -0
  623. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_channel_rbac.py +0 -0
  624. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_checks.py +0 -0
  625. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_checks_lint.py +0 -0
  626. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_cli.py +0 -0
  627. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_cluster.py +0 -0
  628. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_cluster_failover_postgres.py +0 -0
  629. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_cluster_failover_sqlserver.py +0 -0
  630. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_cluster_graph_gating.py +0 -0
  631. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_cluster_lease.py +0 -0
  632. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_code_sets.py +0 -0
  633. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_codeset_edit.py +0 -0
  634. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_config_fingerprint.py +0 -0
  635. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connection_api.py +0 -0
  636. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connection_event_api.py +0 -0
  637. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connection_event_outbound.py +0 -0
  638. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connection_event_scope.py +0 -0
  639. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connection_event_store.py +0 -0
  640. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connection_resilience.py +0 -0
  641. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_connections_cli.py +0 -0
  642. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_consistency.py +0 -0
  643. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_alerts.py +0 -0
  644. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_auth.py +0 -0
  645. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_client.py +0 -0
  646. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_dead_letters.py +0 -0
  647. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_event_log.py +0 -0
  648. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_hardening.py +0 -0
  649. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_icon.py +0 -0
  650. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_password.py +0 -0
  651. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_sessions.py +0 -0
  652. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_shards.py +0 -0
  653. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_status.py +0 -0
  654. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_step_up.py +0 -0
  655. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_theme.py +0 -0
  656. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_users.py +0 -0
  657. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_console_widgets.py +0 -0
  658. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_database_connector_integration.py +0 -0
  659. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_database_transport.py +0 -0
  660. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_db_lookup.py +0 -0
  661. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_db_lookup_live_runner.py +0 -0
  662. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dependency_boundaries.py +0 -0
  663. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dicom_codec.py +0 -0
  664. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dicom_scp.py +0 -0
  665. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dicom_scp_security.py +0 -0
  666. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dicom_scu.py +0 -0
  667. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dicom_wiring.py +0 -0
  668. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dicomweb.py +0 -0
  669. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_docs_runbooks.py +0 -0
  670. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_dryrun.py +0 -0
  671. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ed_documents.py +0 -0
  672. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ed_documents_e2e.py +0 -0
  673. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_egress_allowlist.py +0 -0
  674. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_enginepoll_aggregate.py +0 -0
  675. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_environments.py +0 -0
  676. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_fhir_parsing.py +0 -0
  677. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_fhir_resource.py +0 -0
  678. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_fhir_transport.py +0 -0
  679. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_field_authz.py +0 -0
  680. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_field_authz_metadata.py +0 -0
  681. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_fifo_ordering.py +0 -0
  682. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_generate_cli.py +0 -0
  683. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_generated_adt.py +0 -0
  684. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_generators_core.py +0 -0
  685. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_generators_types.py +0 -0
  686. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_groups.py +0 -0
  687. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_harness.py +0 -0
  688. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_harness_compose.py +0 -0
  689. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_harness_config.py +0 -0
  690. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_harness_faults.py +0 -0
  691. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_harness_file.py +0 -0
  692. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_harness_monitor.py +0 -0
  693. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_harness_scenarios.py +0 -0
  694. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_hl7_core_features.py +0 -0
  695. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_hl7schema.py +0 -0
  696. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_inbound_bind.py +0 -0
  697. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ingest_time.py +0 -0
  698. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_keyprovider.py +0 -0
  699. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_last_admin_guard.py +0 -0
  700. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_last_resort.py +0 -0
  701. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_leader_tasks.py +0 -0
  702. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_listener_tls_exposure.py +0 -0
  703. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_config.py +0 -0
  704. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_corpus.py +0 -0
  705. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_failover_postgres.py +0 -0
  706. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_failover_sqlserver.py +0 -0
  707. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_failover_unit.py +0 -0
  708. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_metrics.py +0 -0
  709. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_profile.py +0 -0
  710. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_report.py +0 -0
  711. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_runner.py +0 -0
  712. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_sender.py +0 -0
  713. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_load_sink.py +0 -0
  714. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_logging.py +0 -0
  715. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_message.py +0 -0
  716. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_message_split.py +0 -0
  717. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_metrics_exporter.py +0 -0
  718. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_mfa.py +0 -0
  719. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_mllp_encoding_override.py +0 -0
  720. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_mllp_tls.py +0 -0
  721. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_nonhl7_ingress_size_cap.py +0 -0
  722. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_operability_config.py +0 -0
  723. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_outbound_signing.py +0 -0
  724. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_outbound_simulate.py +0 -0
  725. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_packaging.py +0 -0
  726. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_parse_tree.py +0 -0
  727. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_parsing.py +0 -0
  728. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_passthrough.py +0 -0
  729. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_passthrough_graph.py +0 -0
  730. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_payload_agnostic_ingress.py +0 -0
  731. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_postgres_store.py +0 -0
  732. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_reconcile_capture.py +0 -0
  733. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_reconcile_compare.py +0 -0
  734. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_reconcile_harness.py +0 -0
  735. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_redaction.py +0 -0
  736. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_reference_sets.py +0 -0
  737. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_reingress.py +0 -0
  738. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_remotefile_transport.py +0 -0
  739. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_response_capture.py +0 -0
  740. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_rest_transport.py +0 -0
  741. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_retention.py +0 -0
  742. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_run_context.py +0 -0
  743. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_scaffold.py +0 -0
  744. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_scaffold_requirements.py +0 -0
  745. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_scan_forbidden.py +0 -0
  746. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_secrets_dpapi.py +0 -0
  747. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_security_notify.py +0 -0
  748. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_security_static.py +0 -0
  749. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_service_control.py +0 -0
  750. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_sharding.py +0 -0
  751. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_sibling_helper_finder.py +0 -0
  752. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_smart_backend.py +0 -0
  753. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_soap_transport.py +0 -0
  754. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_soap_wssecurity.py +0 -0
  755. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_sqlserver_coordinator.py +0 -0
  756. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_sqlserver_cursor_close.py +0 -0
  757. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_sqlserver_schema_init.py +0 -0
  758. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_sqlserver_store.py +0 -0
  759. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_staged_pipeline.py +0 -0
  760. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_startup_fault_isolation.py +0 -0
  761. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_stats_reset.py +0 -0
  762. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_step_up.py +0 -0
  763. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store.py +0 -0
  764. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store_backend.py +0 -0
  765. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store_encryption.py +0 -0
  766. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store_file_hardening.py +0 -0
  767. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store_once_deliver_many.py +0 -0
  768. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store_once_graph.py +0 -0
  769. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store_read_pool.py +0 -0
  770. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_store_ssl.py +0 -0
  771. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_summary.py +0 -0
  772. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_supervisor.py +0 -0
  773. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_task_resilience.py +0 -0
  774. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tcp_transport.py +0 -0
  775. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_cli.py +0 -0
  776. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_compare.py +0 -0
  777. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_correlate.py +0 -0
  778. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_hl7_fields.py +0 -0
  779. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_mefor_api.py +0 -0
  780. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_mllp.py +0 -0
  781. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_relay.py +0 -0
  782. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_report.py +0 -0
  783. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tee_store.py +0 -0
  784. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_timer_source.py +0 -0
  785. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_timezone.py +0 -0
  786. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_tls_policy.py +0 -0
  787. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_totp.py +0 -0
  788. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_totp_window.py +0 -0
  789. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_transform_offloop.py +0 -0
  790. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_transform_state.py +0 -0
  791. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_transports.py +0 -0
  792. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_verify.py +0 -0
  793. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_version.py +0 -0
  794. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_win2025_acceptance.py +0 -0
  795. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_wiring.py +0 -0
  796. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_wiring_reload.py +0 -0
  797. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_wiring_serve.py +0 -0
  798. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_ws_stats_revalidation.py +0 -0
  799. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_x12_parsing.py +0 -0
  800. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_x12_rte.py +0 -0
  801. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_x12_source_ip_allowlist.py +0 -0
  802. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/tests/test_x12_transport.py +0 -0
  803. {messagefoundry-0.2.8 → messagefoundry-0.2.9}/uv.lock +0 -0
@@ -23,9 +23,11 @@ jobs:
23
23
  test:
24
24
  name: test (${{ matrix.os }}, py${{ matrix.python-version }})
25
25
  runs-on: ${{ matrix.os }}
26
- # Wall-clock backstop: bound each leg so a hung test fails in minutes, not the 6h default. The
27
- # pytest-timeout watchdog (60s/test) should catch a culprit first; this is the belt-and-suspenders cap
28
- # if a whole process ever deadlocks below pytest.
26
+ # Wall-clock backstop: bound each leg so a hung test fails in minutes, not the 6h default. Three
27
+ # nested watchdogs catch a hang at increasing scope (#55): the pytest-timeout per-test cap (60s,
28
+ # pyproject addopts) + the faulthandler belt fire FIRST and name the stuck frame; the pytest STEP
29
+ # has its own `timeout-minutes: 13` so a process-level deadlock below pytest fails the step fast;
30
+ # this job cap is the outermost belt if even that is somehow out-raced.
29
31
  timeout-minutes: 15
30
32
  strategy:
31
33
  fail-fast: false
@@ -75,10 +77,27 @@ jobs:
75
77
  - name: Type-check (mypy, strict)
76
78
  run: mypy messagefoundry
77
79
 
80
+ # Step-level watchdog UNDER the 15-min job cap (#55): the windows-2022 leg intermittently
81
+ # wedges ~25% in (a Windows ProactorEventLoop listener-teardown / socket wait that the shared
82
+ # session event loop can't get past), emits no output for ~12 min, then the JOB cap CANCELS it
83
+ # — a red ✗ with no stack and no named test. Two belts make that fail FAST and NAMED instead:
84
+ # * `--timeout-method=thread` (the ONLY method on Windows — SIGALRM is POSIX-only) dumps ALL
85
+ # thread stacks at the per-test cap (60s, set in pyproject addopts), naming the stuck frame.
86
+ # * PYTHONFAULTHANDLER=1 + `-o faulthandler_timeout=90` is the belt that fires even when the
87
+ # thread-timer CANNOT interrupt a main-thread C-level wait (a Proactor overlapped op /
88
+ # blocking accept / subprocess.wait): pytest's faulthandler plugin arms a separate watchdog
89
+ # thread that dumps the NATIVE stack of every thread at 90s (> the 60s pytest-timeout, so the
90
+ # per-test dump is attributed first; this is the last-resort stack when the thread method is
91
+ # itself out-raced). NB the plugin exposes this as the `faulthandler_timeout` ini key, not a
92
+ # `--faulthandler-*` CLI flag, so it is passed with `-o`; it only DUMPS (never kills), safe.
93
+ # The step `timeout-minutes: 13` is the outer backstop, well under the job's 15-min cap, so a
94
+ # hang both watchdogs somehow miss still fails the STEP (not the whole job at the silent cap).
78
95
  - name: Tests (pytest)
96
+ timeout-minutes: 13
79
97
  env:
80
98
  QT_QPA_PLATFORM: offscreen
81
- run: pytest -q
99
+ PYTHONFAULTHANDLER: "1"
100
+ run: pytest -q -o faulthandler_timeout=90
82
101
 
83
102
  # Build + type-check the VS Code extension, and run its integration tests. The Python jobs never
84
103
  # touch ide/, so a dep bump or IDE code change that breaks the bundle or the types would otherwise
@@ -592,7 +611,14 @@ jobs:
592
611
  # install-service.ps1 -Environment threads it into the service command + resolves
593
612
  # environments/prod.toml). INFO not DEBUG: `serve` refuses DEBUG in prod (Gate #1 — DEBUG can
594
613
  # surface PHI); INFO is enough to smoke service start + MLLP.
595
- .\scripts\service\install-service.ps1 -AppExe $exe -LogLevel INFO -Environment prod
614
+ # -LockConfigDir: the runner checks out samples/config with the default ACL, which grants
615
+ # BUILTIN\Users (S-1-5-32-545) write. The in-process config-source trust guard (SEC-003,
616
+ # wiring._assert_safe_config_source_windows) then REFUSES to load it ("writable-by-others
617
+ # path") and `serve` crash-loops to SERVICE_PAUSED, so /health never comes up. Locking the
618
+ # config dir (strip inheritance -> SYSTEM/Administrators only; the LocalSystem service still
619
+ # reads it) is the production-correct posture docs/SERVICE.md prescribes, and exercises the
620
+ # real -LockConfigDir install path rather than the MEFOR_ALLOW_INSECURE_CONFIG_SOURCE dev escape.
621
+ .\scripts\service\install-service.ps1 -AppExe $exe -LogLevel INFO -Environment prod -LockConfigDir
596
622
  # The shipped samples graph includes a mutual-TLS WS-* SOAP feed (IB_IMMUNIZATION_VXU) whose
597
623
  # connector LOADS its client cert at wiring time, so the engine refuses to start the graph
598
624
  # without a readable cert+key. Mint a throwaway pair for the smoke — the smoke sends only an
@@ -6,6 +6,63 @@ All notable changes to MessageFoundry are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.2.9] — 2026-06-27 — Early Access
10
+
11
+ A retention + security-hardening + observability release: per-connection retention and
12
+ embedded-document pruning windows, dual-control config reloads with startup code-attestation,
13
+ operational-health metrics, and a fix for the intermittent Windows listener-teardown / CI hang.
14
+
15
+ ### Added
16
+ - **Per-connection retention windows (ADR 0027).** Optional `messages_days` (inbound) and
17
+ `dead_letter_days` (outbound) on a connection, layered over the global `[retention]` window and
18
+ authored on the connection spec or `connections.toml` (the same override idiom as the delivery
19
+ knobs): `None` inherits the global window, `0` keeps forever. The `RetentionRunner` threads a
20
+ per-connection cutoff through the body and dead-letter purge on **all three** store backends; the
21
+ never-purge-an-in-flight-body guard and the single per-pass audit row (now recording the overrides)
22
+ are unchanged. (#34)
23
+ - **Embedded-document pruning (ADR 0042).** Optional `prune_documents_after` (+ a size threshold)
24
+ per inbound connection: after the window, bulky **base64 embedded documents** — HL7 **OBX-5 ED**
25
+ and the generic `mfb64:v1:` carriage — are stripped **in place** to a small size/content-type
26
+ tombstone (via the parsed model / codec, **never** string-slicing HL7), keeping the rest of the
27
+ message parseable; the row is never deleted and a `documents_pruned` flag is set. All three
28
+ backends. (The ingest-time offload variant remains deferred.) (#47)
29
+ - **Dual-control `config:reload` (ADR 0041 D2).** `config_reload` is now a gateable
30
+ `[approvals].operations` op — a **distinct** second approver must release a live config reload
31
+ (the requester can never self-approve; both identities land in the hash-chained audit). Opt-in /
32
+ deny-by-default, so single-operator deployments are unchanged. (#53)
33
+ - **Startup code self-attestation (ADR 0041 D3).** At startup the engine hashes its loaded modules
34
+ against the wheel's `dist-info/RECORD`; on drift it records a hash-chained, off-box-teed
35
+ `startup_integrity` audit row and raises an alert (**alert-only by default**; opt-in
36
+ `[integrity].fail_closed_on_drift` refuses to start). A no-op on an editable (`pip install -e .`)
37
+ install, so development is never bricked. (#54)
38
+ - **Operational-health metrics.** `GET /status` now meters the app-log directory's disk usage
39
+ alongside the database, and a per-connection **message-stall** alert rule fires when a connection's
40
+ oldest-undelivered age crosses a configurable threshold. (#50)
41
+
42
+ ### Changed
43
+ - **Non-editable, hash-locked wheel is the enforced production default (ADR 0017 amendment).** The
44
+ prior recommendation is now the default for production deployments; editable installs remain a
45
+ no-op for development. (#54)
46
+
47
+ ### Fixed
48
+ - **Intermittent Windows listener-teardown hang.** `MLLPSource` / `TcpSource` / `X12Source` no longer
49
+ `await server.wait_closed()` / `writer.wait_closed()` **unbounded** on the Windows Proactor loop
50
+ during teardown — a wait that never completes can no longer stall a shared event loop (the same
51
+ class as the resolved py3.11 hang). Added CI guards (a per-test `faulthandler` stack dump and a
52
+ step-level watchdog) so a future hang fails fast and names itself instead of silently timing out. (#55)
53
+
54
+ ### Docs
55
+ - Refreshed `benchmarks/TUNING-BASELINE.md` with measured multi-process sharding throughput from the
56
+ Windows Server 2025 box (η ≈ 0.85 speedup shape; per-shard E_core ≈ 42 msg/s — a test-box SQLite
57
+ floor), plus the still-unmeasured hardware-gated follow-ups (enterprise E_core, the shared-DB
58
+ commit-wall sweep). (#28, #29)
59
+ - Authored **ADR 0027** (per-connection retention) and **ADR 0042** (embedded-document pruning); added
60
+ EARS acceptance criteria to **ADR 0041** D2/D3; amended **ADR 0017** for the enforced wheel.
61
+
62
+ ### CI
63
+ - Locked the smoke job's config directory (#603) and skipped a mirror-only Dependabot guardrail test
64
+ on the OSS mirror (#606), greening `main` CI post-0.2.8.
65
+
9
66
  ## [0.2.8] — 2026-06-27 — Early Access
10
67
 
11
68
  A tooling/ops release: the load harness gains a **multi-shard driver** so one harness can drive a
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: messagefoundry
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Open-source healthcare integration engine — route, transform, and validate messages across many formats and connection types
5
5
  Project-URL: Homepage, https://messagefoundry.org/
6
6
  Project-URL: Documentation, https://messagefoundry.org/
@@ -390,6 +390,7 @@ the rest are forward-compat placeholders for the future engine broker (accepted-
390
390
  |---|---|---|---|
391
391
  | `level` | enum | `info` | log level; never run prod at `debug` (PHI) — `serve` refuses it (Gate #1) |
392
392
  | `format` | enum | `text` | stdout rendering: `text` (default) or structured `json` (one object per line). Stdlib only — no structlog |
393
+ | `log_dir` | str | _unset_ | the directory NSSM (or another supervisor) **rotates the engine's captured stdout/stderr into**. The engine never writes log **files** itself (it logs to stdout); set this only to tell it where the supervisor parks them, and `GET /status` then **meters that directory's total bytes + filesystem free space** alongside the DB metrics (#50). Unset = stdout-only, no metering. **Metadata only** — the file contents are never read. |
393
394
  | `forward_enabled` | bool | `false` | ship a copy of every record off-box to a syslog/SIEM collector (sec-offbox-log) so evidence survives a host compromise; requires `forward_host` |
394
395
  | `forward_host` | str | — | syslog/SIEM collector host (**required** when `forward_enabled`) |
395
396
  | `forward_port` | int | `514` | collector port (1–65535) |
@@ -412,12 +413,21 @@ so retention is opt-in.
412
413
  | `messages_days` | int | `0` | past N days, null inbound bodies (`raw`/`summary`/`error`) of **fully-resolved** messages (no `pending`/`inflight` delivery), keeping metadata. `0` = keep |
413
414
  | `dead_letter_days` | int | `0` | past N days, null the bodies of **dead-lettered** outbound rows (their own window — a dead row stays replayable until purged). `0` = keep |
414
415
  | `state_max_age_days` | int | `0` | past N days, **delete** transform-state entries (ADR 0005) last written before the cutoff — keeps the in-memory state cache + table bounded. A simple global age purge (by `set_at`); per-namespace policy is a follow-up. `0` = keep |
416
+ | `connection_event_retention_hours` | int | `0` | past N **hours**, **delete** `connection_event` rows (the `[diagnostics]` #46 transport/lifecycle log — high-volume under a connect-per-message sender or a probe storm, so its own short window in **hours**, not days). `0` = inherit the `messages_days` body window (the ADR 0021 §7.5 default). |
415
417
  | `audit_days` | int | `0` | **reserved / not enforced.** The `audit_log` is a tamper-evident hash chain and HIPAA expects ~6-year retention, so audit is **keep-forever by design**; archive-first pruning is a tracked follow-up. Accepted so a forward-looking file still loads |
416
418
  | `max_db_mb` | int | `0` | advisory only: warn (WARNING log + an `AlertSink` `storage_threshold` event) when the DB (+ `-wal`/`-shm`) exceeds this. Never auto-deletes. `0` = off |
417
419
  | `purge_interval_seconds` | float | `3600` | how often the purge/maintenance loop runs a pass |
418
420
  | `wal_checkpoint_seconds` | float | `0` | `PRAGMA wal_checkpoint(TRUNCATE)` cadence (SQLite). `0` = off (rely on auto-checkpoint). Evaluated once per pass, so a value below `purge_interval_seconds` is effectively rounded up to it |
419
421
  | `vacuum_at` | str | `""` | daily local `"HH:MM"` to run `VACUUM` (SQLite; reclaims space freed by purges). `""` = off. A daily off-peak time, **not** a cron expression (no new dependency); VACUUM holds a write lock on the whole DB while it runs |
420
422
 
423
+ > **Per-connection overrides ([ADR 0027](adr/0027-per-connection-retention.md)).** `messages_days` and
424
+ > `dead_letter_days` are **global defaults** an individual connection may override: an **inbound** sets its
425
+ > own `messages_days`, an **outbound** its own `dead_letter_days` (both `None` = inherit this global window,
426
+ > `0` = keep that connection's bodies forever, `>0` = days). An inbound may also opt into **embedded-document
427
+ > pruning** (`prune_documents_after` + `prune_documents_min_bytes`, [ADR 0042](adr/0042-embedded-document-pruning.md))
428
+ > to strip bulky base64 attachments while keeping the readable message. These live on the connection (code-first
429
+ > or in `connections.toml`) — see [CONNECTIONS.md](CONNECTIONS.md).
430
+
421
431
  > **SQLite-only.** Retention/maintenance runs on the SQLite backend. On the SQL Server
422
432
  > backend it is a DBA concern (TDE + a SQL Agent purge/shrink job). Each pass that does real work
423
433
  > writes one `retention_purge` `audit_log` entry (cutoffs + counts, **no** message content). Design:
@@ -432,6 +442,7 @@ so retention is opt-in.
432
442
  | `internal_error` | enum | `continue` | what a delivery worker does on an **internal/code error** (a non-`DeliveryError` exception from `send` — our bug, not the partner's): `continue` (dead-letter the row + advance) or `stop` (halt the connection's worker, preserve the message for replay, raise a `connection_stopped` alert). Per-outbound `internal_error=` overrides. Partner NAKs / transport failures are unaffected. |
433
443
  | `buildup_max_depth` | int | _unset_ | raise a `queue_buildup` alert when an outbound lane's pending depth reaches this. Unset = depth dimension off (a healthy ceiling is throughput-specific, so there's no safe default). Per-outbound `buildup=BuildupThreshold(...)` overrides. |
434
444
  | `buildup_max_oldest_seconds` | num | 300 | raise `queue_buildup` when the lane's **oldest** pending message has waited this long (a stuck/retry-forever head is the classic cause). On by default — a head stuck >5 min is a problem in any environment. Set to unset/`0`-disable via a per-outbound override. |
445
+ | `stall_max_oldest_seconds` | num | _unset_ | raise a `message_stall` alert (Corepoint "Max Message Stall", [ADR 0014](adr/0014-alert-routing-rules.md)) when an outbound lane's **oldest undelivered message** has waited this long. **Unset (the default) = the stall alert is OFF** — deny-by-default/opt-in, because it overlaps `buildup_max_oldest_seconds`'s age dimension and would double-page if both fired. Set a threshold to turn it on; a per-outbound `stall=StallThreshold(...)` overrides it. The stall event routes through `[[alerts.rules]]` like any other ([ADR 0014](adr/0014-alerting-rules-engine.md)). |
435
446
  | `outbox_workers` | int | per-outbound | delivery concurrency (planned) |
436
447
  | `dead_letter` | enum | `keep` | `keep`/`drop`-after-N (planned) |
437
448
 
@@ -440,6 +451,22 @@ so retention is opt-in.
440
451
  |---|---|---|---|
441
452
  | `max_correlation_depth` | int (≥1) | 8 | **Re-ingress loop cap** (ADR 0013 Increment 2). When a captured reply is re-ingressed (`reingress_to=`/`Loopback()`), the re-ingressed message carries a `correlation_depth`; a message at this depth still routes, but the next hop (depth+1) **dead-letters** its re-ingress work-row and marks the origin `ERROR`. Coarse by design — it bounds *total work*, not topology, so a chain that legitimately bounces A→B→A a few times needs headroom. 8 is safe for typical request→response→route feeds; raise it for deep correlation chains, lower it to fence a misbehaving loop. (A value of 0 would dead-letter every re-ingress, so the floor is 1.) |
442
453
 
454
+ ### `[diagnostics]`
455
+ The Corepoint-style **event log** (#46) — a metadata-only record of connection lifecycle / pre-ingress
456
+ failures and the ACK/NAK the engine returns. **Both master switches are on by default and safe to be:**
457
+ they store only non-PHI metadata (connection name, peer IP, a scrubbed reason, the ACK disposition), and
458
+ the AA-ACK *body* is stored only when the store is encrypted (else NULL); a NAK body is never persisted.
459
+ A per-connection `capture_connection_errors` / `capture_ack` flag overrides the matching master switch for
460
+ one connection (see [CONNECTIONS.md](CONNECTIONS.md)).
461
+
462
+ | Key | Type | Default | Notes |
463
+ |---|---|---|---|
464
+ | `connection_events` | bool | `true` | master switch for the **connection/transport event log**: inbound lifecycle (established/closed) + pre-ingress failures (allowlist/capacity/oversize/peer-reset/framing) + outbound lane transitions (connection_lost/restored). Metadata-only, written off the hot path by a drain task. Per-connection `capture_connection_errors` overrides it. |
465
+ | `response_sent` | bool | `true` | master switch for **"Response Sent"** — the ACK/NAK returned to an inbound sender. Always captures the disposition metadata (`ack_code`/`phase`/`outcome`); the AA body is stored only on an encrypted store, and every NAK body is NULL. Per-connection `capture_ack` overrides it. |
466
+
467
+ > Retention for the event log has its own short window — `[retention].connection_event_retention_hours`
468
+ > (in **hours**; `0` = inherit `messages_days`).
469
+
443
470
  ### `[egress]`
444
471
  Fail-closed **outbound destination allowlist** (WP-11c; ASVS 13.2.4/13.2.5/14.2.3) — bounds where the
445
472
  engine may **send** PHI, so a fat-fingered or hostile destination can't exfiltrate it. Each list is
@@ -484,7 +511,8 @@ bytes/SQL leave the box) and retains the would-send payload for parity compariso
484
511
  > the message just finalizes `PROCESSED`.
485
512
 
486
513
  ### `[alerts]`
487
- Where the delivery pipeline's operational alerts (`connection_stopped`, `queue_buildup`) are
514
+ Where the delivery pipeline's operational alerts (e.g. `connection_stopped`, `queue_buildup`,
515
+ `connection_error`, `message_stall`, `integrity_drift`) are
488
516
  delivered. **Both transports are off by default** — with neither configured, events are logged at
489
517
  `WARNING` (the `LoggingAlertSink`). A transport turns on when its essentials are present. Payloads
490
518
  carry the connection name + queue shape only — **never a message body** (no PHI). Delivery is
@@ -515,7 +543,7 @@ silences an event you didn't name. Matching is pure config (no code/`eval`).
515
543
 
516
544
  | Key | Type | Default | Notes |
517
545
  |---|---|---|---|
518
- | `event_type` | str | `any` | match this event: `any`, `connection_stopped`, `queue_buildup`, `storage_threshold`, or `cert_expiry` |
546
+ | `event_type` | str | `any` | match this event: `any`, `connection_stopped`, `queue_buildup`, `storage_threshold`, `cert_expiry`, `connection_error`, `message_stall`, or `integrity_drift` |
519
547
  | `connection` | str (glob) | `*` | glob over the connection name (e.g. `OB_*`, `IB_ACME_*`) |
520
548
  | `min_depth` | int | _unset_ | `queue_buildup` only — match only when pending depth is at/over this |
521
549
  | `min_oldest_seconds` | num | _unset_ | `queue_buildup` only — …or the oldest pending message has waited at least this long |
@@ -708,6 +736,21 @@ Optional **dual-control (maker-checker)** approval for high-value actions (ASVS
708
736
  | `operations` | list[str] | `["connection_purge", "dead_letter_replay"]` | which operations require approval; each must be a known op key (a typo is refused at startup) |
709
737
  | `expiry_hours` | num | 72 | a pending request can no longer be approved after this many hours (`0` = never expires) |
710
738
 
739
+ ### `[integrity]`
740
+ Startup **self-attestation of the installed engine wheel** ([ADR 0041](adr/0041-load-path-attestation-and-change-attribution.md)
741
+ D3) — a runtime in-place-tamper tripwire (`messagefoundry/integrity.py`). At startup (and on demand) the
742
+ engine hashes every **loaded** first-party `messagefoundry` module file against the installed wheel's
743
+ `*.dist-info/RECORD` baseline; on **drift** (a loaded module no longer matching its RECORD hash) it records
744
+ a hash-chained `startup_integrity` audit row and fires the `AlertSink`. It complements ADR 0036 (which guards
745
+ the *config dir*) by covering the installed *site-packages* an admin with venv-write + restart rights could
746
+ edit in place. Both keys default **safe**: attestation is on but **alert-only** (it never blocks startup), and
747
+ an **editable** install (`pip install -e .` — no RECORD baseline) is a **no-op**, so dev is never bricked.
748
+
749
+ | Key | Type | Default | Notes |
750
+ |---|---|---|---|
751
+ | `enabled` | bool | `true` | run startup attestation at all. On by default (alert-only is harmless); a **no-op** off an editable install. Set `false` only to suppress the check entirely (e.g. an unusual packaging where RECORD is known-stale) — you then lose the in-place-tamper tripwire. |
752
+ | `fail_closed_on_drift` | bool | `false` | when `true`, drift makes `serve` **refuse to start** (after recording the audit row + alerting). Default `false` = **alert-only**: a legitimate reviewed in-place security hotfix (the documented vendored-parser patch contingency) would itself trip a RECORD mismatch, so fail-closed-by-default would brick a legitimate patch. Opt in for hard enforcement on a locked-down instance. |
753
+
711
754
  ### `[engine]`
712
755
  | Key | Type | Default | Notes |
713
756
  |---|---|---|---|
@@ -173,7 +173,8 @@ collision.
173
173
  | `tls_check_hostname` | out | `true` | require the server cert to match `host` (SNI + hostname check). |
174
174
 
175
175
  Plus on `inbound(...)`: `ack_mode` (`original`/`enhanced`/`none`), `strict`, `hl7_version`. On
176
- `outbound(...)`: `retry` (`RetryPolicy`), `ordering`, `internal_error`, `buildup`, and `simulate`
176
+ `outbound(...)`: `retry` (`RetryPolicy`), `ordering`, `internal_error`, `buildup`, `stall`
177
+ (`StallThreshold` — Corepoint "Max Message Stall", #50; off unless set, see below), and `simulate`
177
178
  (`bool`, default `false`). `simulate=True` puts the outbound in **shadow / parallel-run mode** (#15): it
178
179
  runs the full transform + count-and-log and finalizes the message `PROCESSED`, but **suppresses the real
179
180
  egress** (no bytes/SQL leave the box) and retains the would-send payload for parity comparison — so a
@@ -1011,6 +1012,90 @@ outbound("MLLP-OUT_PAYER_ELIG", MLLP(host=env("payer_host"), port=2575, reingres
1011
1012
  # a Handler Sends the eligibility query to MLLP-OUT_PAYER_ELIG; its reply re-ingresses into IB-LOOP_PAYER_ELIG.
1012
1013
  ```
1013
1014
 
1015
+ ## Per-connection retention, document pruning & diagnostics overrides
1016
+
1017
+ A connection may **override** several service-wide `[…]` defaults for just itself. Each is set the same
1018
+ two ways as `retry`/`buildup` — **code-first** on `inbound(...)`/`outbound(...)`, **or** as a key in
1019
+ `connections.toml` (ADR 0007) — and each defaults to **inherit the global setting** when omitted.
1020
+
1021
+ ### Retention overrides ([ADR 0027](adr/0027-per-connection-retention.md))
1022
+
1023
+ Override the global `[retention]` body-null windows per connection. `None` (omitted) = inherit the global
1024
+ window; `0` = keep this connection's bodies **forever**; `>0` = days.
1025
+
1026
+ | Key | Dir | Type | Default | Meaning |
1027
+ |-----|-----|------|---------|---------|
1028
+ | `messages_days` | in | int | inherit `[retention].messages_days` | past N days, null this **inbound's** received message bodies (keyed on the receiving inbound), keeping the metadata row. `0` = keep forever |
1029
+ | `dead_letter_days` | out | int | inherit `[retention].dead_letter_days` | past N days, null the bodies of **this outbound's** dead-lettered rows (keyed on the outbound that dead-lettered them). A dead row stays replayable until its body is purged. `0` = keep forever |
1030
+
1031
+ ### Embedded-document pruning ([ADR 0042](adr/0042-embedded-document-pruning.md), #47)
1032
+
1033
+ A separate **inbound** lever that evicts only the bulky base64 **embedded document** (a `mfb64:v1:`
1034
+ carriage value / an HL7 `OBX-5` ED embed) **in place** to a small tombstone — keeping the surrounding,
1035
+ readable message — distinct from `messages_days`, which nulls the **whole** body.
1036
+
1037
+ | Key | Dir | Type | Default | Meaning |
1038
+ |-----|-----|------|---------|---------|
1039
+ | `prune_documents_after` | in | int | `None` = **never prune** (back-compat) | after N **days**, strip each embedded document for this inbound. Must be `> 0` |
1040
+ | `prune_documents_min_bytes` | in | int | `None` = strip **any** size | skip an embed whose decoded size is **below** this byte threshold (keep small embeds, evict only the bulky ones). Setting it **requires** `prune_documents_after` (else a wiring error) |
1041
+
1042
+ ### Diagnostics / event-log overrides ([ADR 0021](adr/0021-inbound-ack-nak-capture-response-sent.md), #46)
1043
+
1044
+ Override the `[diagnostics]` master switches for one connection. **Tri-state:** omitted = inherit the
1045
+ matching master switch; `true`/`false` = explicit per-connection override.
1046
+
1047
+ | Key | Dir | Type | Default | Meaning |
1048
+ |-----|-----|------|---------|---------|
1049
+ | `capture_ack` | in | bool | inherit `[diagnostics].response_sent` | record the **"Response Sent"** ACK/NAK metadata for this inbound (the AA body only on an encrypted store; a NAK body is never stored) |
1050
+ | `capture_connection_errors` | in | bool | inherit `[diagnostics].connection_events` | record this connection's **lifecycle + pre-ingress failure** events (established/closed, allowlist/capacity/oversize/peer-reset/framing) |
1051
+
1052
+ ### `stall` — Max Message Stall ([ADR 0014](adr/0014-alerting-rules-engine.md), #50)
1053
+
1054
+ An **outbound** override of the `[delivery].stall_max_oldest_seconds` global: raise a `message_stall`
1055
+ alert when this lane's **oldest undelivered message** has waited too long.
1056
+
1057
+ | Key | Dir | Type | Default | Meaning |
1058
+ |-----|-----|------|---------|---------|
1059
+ | `stall` | out | `StallThreshold` | inherit `[delivery]` (off unless set) | `StallThreshold(max_oldest_seconds=…)` — `None` keeps the stall alert **off** (it overlaps `buildup`'s age dimension, so it's opt-in to avoid double-paging). In `connections.toml` it is an `[outbound.stall]` table with `max_oldest_seconds` (see the example below) |
1060
+
1061
+ ```python
1062
+ from messagefoundry import MLLP, inbound, outbound
1063
+ from messagefoundry.config.models import StallThreshold
1064
+
1065
+ # Inbound: keep this feed's bodies only 7 days, and prune embedded documents >256 KiB after 1 day.
1066
+ inbound("IB_ACME_RAD", MLLP(port=2576), router="rad_router",
1067
+ messages_days=7, prune_documents_after=1, prune_documents_min_bytes=256 * 1024,
1068
+ capture_ack=True) # force-capture the ACK even if the master switch is off
1069
+
1070
+ # Outbound: keep this destination's dead-letter bodies 90 days; alert if a message stalls >10 min.
1071
+ outbound("OB_PACS_RAD", MLLP(host="pacs", port=11112),
1072
+ dead_letter_days=90, stall=StallThreshold(max_oldest_seconds=600))
1073
+ ```
1074
+
1075
+ ```toml
1076
+ # connections.toml — the same overrides as data.
1077
+ [[inbound]]
1078
+ name = "IB_ACME_RAD"
1079
+ transport = "mllp"
1080
+ router = "rad_router"
1081
+ messages_days = 7
1082
+ prune_documents_after = 1
1083
+ prune_documents_min_bytes = 262144
1084
+ capture_ack = true
1085
+ [inbound.settings]
1086
+ port = 2576
1087
+
1088
+ [[outbound]]
1089
+ name = "OB_PACS_RAD"
1090
+ transport = "mllp"
1091
+ dead_letter_days = 90
1092
+ [outbound.settings]
1093
+ host = { env = "pacs_host" }
1094
+ port = 11112
1095
+ [outbound.stall]
1096
+ max_oldest_seconds = 600
1097
+ ```
1098
+
1014
1099
  ## Resource management & limits (ASVS 13.1.2 / 13.1.3 / 13.2.6)
1015
1100
 
1016
1101
  How the engine bounds connections, threads, and retries per external system, and what happens **when a
@@ -215,3 +215,42 @@ installs use the pinned wheel. That migration already had to repurpose the built
215
215
  the security-posture tier — both Blocker rows must land together.
216
216
  - Most of the model already works; the remaining effort is **packaging, documentation, scaffolding, one
217
217
  env-name lift, and a few isolation/drift guards** — not a redesign of the config or value layers.
218
+
219
+ ## Amendment (2026-06-27) — non-editable wheel from recommendation to enforced production default
220
+
221
+ > Append-only amendment from the **insider-code-tampering review** (see
222
+ > [ADR 0041](0041-load-path-attestation-and-change-attribution.md) D3, BACKLOG #54). It **does not rewrite**
223
+ > the accepted three-tier model or the eight ratified decisions above — it **tightens** Ratified Decision 5
224
+ > ("Boundary enforcement → packaging-primary") from a documented *recommendation* into an **enforced
225
+ > production default**.
226
+
227
+ **What changes.** The original decision said the non-editable wheel is the *recommended* boundary and an
228
+ optional Windows venv ACL-lock is *defense-in-depth*. ADR 0041 D3 adds a **runtime tripwire** that converts
229
+ this from advice into an enforced posture:
230
+
231
+ - The **non-editable, hash-locked wheel is the production default.** Editable `pip install -e .` is
232
+ **retired from production deployment docs** ([EARLY-ADOPTER-GUIDE.md](../EARLY-ADOPTER-GUIDE.md),
233
+ [DEPLOYMENT.md](../DEPLOYMENT.md), SERVICE.md): editable installs are documented **only** for engine
234
+ co-development, never for a deployed instance. The two-repo consumer model (pinned wheel + org config repo)
235
+ is now the single documented production install path.
236
+ - Enforcement is **startup self-attestation** (ADR 0041 D3): the engine hashes its loaded `messagefoundry`
237
+ module files against the wheel's `*.dist-info/RECORD` baseline at boot. On drift the **default is
238
+ alert-only** (a `startup_integrity` audit row + `AlertSink`); an **opt-in** `[integrity].fail_closed_on_drift`
239
+ hard-refuses to start. This makes the read-only-engine boundary **detectable at runtime**, not merely
240
+ enforced by file packaging.
241
+
242
+ **Implemented as a no-op on editable dev installs.** An editable install has **no `dist-info/RECORD`**
243
+ baseline to attest against, so the tripwire is a **no-op/advisory** there — `pip install -e ../MessageFoundry`
244
+ during co-development (the workflow named in *First instance of the pattern* above) is **byte-for-byte
245
+ unchanged** and never bricked. The enforcement applies precisely where it should: a **deployed, wheel-installed
246
+ production instance**.
247
+
248
+ **Why the default is alert-only, not fail-closed.** The documented vendored-patch contingency for the dormant
249
+ `python-hl7`/`hl7apy` parsers (a legitimate, reviewed security hotfix applied in place) would itself trip a
250
+ `RECORD` mismatch. A fail-closed-by-default posture would therefore **brick a legitimate security patch** at
251
+ the worst moment. Alert-only-by-default detects-and-attributes the drift while keeping the service up;
252
+ operators who want hard enforcement opt in via `[integrity].fail_closed_on_drift`.
253
+
254
+ **What this does not change.** The accepted three-tier ownership model, the same-commit-everywhere promotion
255
+ model (Decision 4), the env-name decoupling Blockers, and the AGPL/licensing posture (Decision 6) are all
256
+ unchanged. This amendment narrows **only** the install/boundary-enforcement surface of Decision 5.
@@ -0,0 +1,208 @@
1
+ # ADR 0027 — Per-connection retention / pruning windows
2
+
3
+ - **Status:** Proposed <!-- Proposed (no code yet) → Accepted (build may start) → Superseded by NNNN / Rejected -->
4
+ - **Date:** 2026-06-27
5
+ - **Related:** BACKLOG #34 · [ADR 0001](0001-staged-pipeline-architecture.md) (staged queue + the
6
+ count-and-log / at-least-once invariants this purge must preserve) · [ADR 0007](0007-gui-manageable-connections-toml.md)
7
+ (transport-config-as-data — the per-connection keys are also hand-/GUI-editable) ·
8
+ [ADR 0021 §7](0021-inbound-ack-nak-capture-response-sent.md) (the `connection_event` log + the **#46
9
+ per-connection diagnostics-override plumbing this reuses**) · [ADR 0005](0005-transform-accessible-state.md)
10
+ (transform-state purge — stays global) · [ADR 0017](0017-consumer-deployment-model.md) (org-owned config
11
+ repo across instances) · [CLAUDE.md](../../CLAUDE.md) §1 (no grouping unit; connections may be data),
12
+ §2 (count-and-log + reliability), §9 ([PHI.md](../PHI.md) §8 retention) ·
13
+ [`config/settings.py`](../../messagefoundry/config/settings.py) `RetentionSettings`/`DiagnosticsSettings` ·
14
+ [`config/wiring.py`](../../messagefoundry/config/wiring.py) `InboundConnection`/`OutboundConnection` ·
15
+ [`pipeline/retention.py`](../../messagefoundry/pipeline/retention.py) `RetentionRunner.run_once` ·
16
+ [`store/store.py`](../../messagefoundry/store/store.py) `purge_message_bodies`/`purge_dead_letters`
17
+
18
+ ---
19
+
20
+ ## Context
21
+
22
+ Data retention today is a **single, store-wide policy**. The `[retention]` service-settings section
23
+ ([`config/settings.py`](../../messagefoundry/config/settings.py) `RetentionSettings`) is enforced by
24
+ **one** global [`RetentionRunner`](../../messagefoundry/pipeline/retention.py) per process. Its windows
25
+ (`messages_days`, `dead_letter_days`) drive the store purge methods — `purge_message_bodies` nulls inbound
26
+ message bodies, `purge_dead_letters` nulls dead-lettered outbound bodies — and each takes a **single
27
+ `older_than` cutoff and purges store-wide by message age only**. The inbound `InboundConnection` and
28
+ outbound `OutboundConnection` ([`config/wiring.py`](../../messagefoundry/config/wiring.py)) carry no
29
+ retention field. So every feed shares one window: an operator cannot keep ADT for 90 days while pruning a
30
+ high-volume / low-value lab feed at 7, or null bodies sooner for one chatty connection to bound its PHI
31
+ footprint feed-by-feed. Mirth, by contrast, sets **message storage + pruning per channel** — the standard
32
+ operator lever for bounding PHI footprint feed-by-feed.
33
+
34
+ The mechanism to layer a per-connection override over a global default **already exists and was just
35
+ extended** for the #46 Corepoint-style event log ([ADR 0021 §7](0021-inbound-ack-nak-capture-response-sent.md),
36
+ PR #541): `InboundConnection.capture_ack` / `capture_connection_errors` are `bool | None` where
37
+ **`None` = inherit the matching `[diagnostics]` master switch** and an explicit value overrides it for one
38
+ connection — the same shape as `OutboundConnection.retry`/`ordering`/`buildup`
39
+ (`RetryPolicy`/`OrderingMode`/`BuildupThreshold`) and the inbound FIFO binding. The `inbound()`/`outbound()`
40
+ factories thread the field through `build_inbound_connection`/`build_outbound_connection`, and the ADR 0007
41
+ `connections.toml` loader desugars the same key through those same factories. Critically,
42
+ `retention.py run_once` **already interleaves** body-purge **and** the #46 `connection_event` purge in **one
43
+ pass** (the RETENTION hook). This ADR extends that **same** pass and **reuses that same override plumbing**
44
+ rather than inventing a parallel one.
45
+
46
+ Two [CLAUDE.md](../../CLAUDE.md) invariants bound the design and **must not** be relaxed:
47
+
48
+ - **Count-and-log** (§2): "**every received message is persisted before the ACK** … nothing is
49
+ accepted-and-dropped." A purge therefore **NULLs the PHI *body* while keeping the metadata row** (counts,
50
+ disposition, audit intact — the Mirth Data-Pruner pattern, `purge_message_bodies`' existing contract); it
51
+ never deletes a `messages` row.
52
+ - **Reliability / at-least-once** (§2, ADR 0001): a body still in flight is never purged
53
+ (`purge_message_bodies` already guards `NOT EXISTS (… queue.status IN pending/inflight)`); a per-connection
54
+ cutoff only changes *which age* is eligible, never that guard.
55
+ - **No grouping unit / connections may be data** (§1): "*Routers/Handlers (logic) stay code-first*, but a
56
+ Connection's *transport config* … may live in an optional **`connections.toml`**." Retention is transport
57
+ *config* for a connection, so the override rides the connection spec + `connections.toml`, **not** a
58
+ Router/Handler API and **not** a built "channel" object.
59
+
60
+ ## Decision
61
+
62
+ **Add a per-connection retention override layered over the global `[retention]` default, authored on the
63
+ inbound/outbound connection (code-first **and** `connections.toml`), and thread a per-connection cutoff into
64
+ the existing purge SQL** — reusing the #46 override pattern, not a new one.
65
+
66
+ ### D1 — Override field on the connection spec (= #46 / FIFO / RetryPolicy / BuildupThreshold)
67
+
68
+ Add `messages_days: int | None` to `InboundConnection` and `dead_letter_days: int | None` to
69
+ `OutboundConnection` (and their `inbound()` / `outbound()` factories + `build_inbound_connection` /
70
+ `build_outbound_connection` cores), where **`None` = inherit the global `[retention]` window** and an
71
+ explicit value overrides it for that one connection (`0` = keep-forever, `>0` = days). Authored code-first
72
+ (`inbound(..., messages_days=90)`) **and** as a `connections.toml` key (ADR 0007 desugars through the same
73
+ factory), so it stays hand- and GUI-editable. This is the **identical** override idiom #46 just shipped for
74
+ `capture_ack`/`capture_connection_errors` — no new settings section, no new resolver.
75
+
76
+ - `messages_days` rides the **inbound** because `purge_message_bodies` is keyed by the receiving connection
77
+ (`messages.channel_id` = inbound name). `dead_letter_days` rides the **outbound** because
78
+ `purge_dead_letters` is keyed by the connection that dead-lettered the row (`queue.destination_name` =
79
+ outbound name).
80
+
81
+ ### D2 — Thread a per-connection cutoff through the purge SQL on all three backends
82
+
83
+ The `RetentionRunner` resolves, per pass, a **`{connection_name → older_than}` map** (per-connection override
84
+ → global `[retention]` default → keep-forever) and passes it to the purge methods alongside the global
85
+ cutoff. `purge_message_bodies` (keyed on `messages.channel_id`) / `purge_dead_letters` (keyed on
86
+ `queue.destination_name`) gain an **optional per-connection-cutoff argument** (default empty ⇒ byte-identical
87
+ to today's single global cutoff): a connection in the map is purged at its own cutoff; any connection absent
88
+ from the map falls back to the global window. The per-connection cutoff predicate is **AND-ed** with the
89
+ existing *never-purge-an-in-flight-body* predicate (`NOT EXISTS (pending/inflight)`), so a purge can never
90
+ evict a body still being routed/transformed/delivered. This must land on **all three** store backends
91
+ (**SQLite / Postgres / SQL Server**) with a purge-SQL parity test. Lane A is the **sole store-writer** —
92
+ coordinate land-order with the pool-prewarm store refactor so the purge-SQL change rebases cleanly onto the
93
+ shared read pool.
94
+
95
+ ### D3 — One audit row per pass, recording per-connection cutoffs + counts
96
+
97
+ `RetentionRunner.run_once` still emits **exactly one** `retention_purge` `audit_log` entry per pass that did
98
+ work, now recording the **per-connection cutoffs + per-connection purged counts** (connection name + days +
99
+ count — **never** message content, no PHI) alongside the existing global fields. This is the same
100
+ count-and-log discipline the global runner already follows, and the same single pass that already interleaves
101
+ the #46 `connection_event` purge.
102
+
103
+ ### What this must not break
104
+
105
+ - **Count-and-log / Mirth Data-Pruner.** Still null-body-keep-metadata — never delete a `messages` row;
106
+ counts, disposition, and the audit trail stay intact. A per-connection cutoff changes *when* a body is
107
+ nulled, never *that the row survives*.
108
+ - **At-least-once / reliability (ADR 0001).** The `NOT EXISTS (pending/inflight)` in-flight guard is
109
+ AND-ed in unchanged — a message mid-pipeline is never purged regardless of its connection's window.
110
+ - **No grouping unit / code-first logic.** The override is connection transport-config (spec field +
111
+ `connections.toml`); Router/Handler *logic* is untouched. No declarative "channel" element.
112
+ - **Global-only deployments.** Every new field defaults to `None` (inherit); a config with no per-connection
113
+ override resolves to exactly one global cutoff and the purge SQL is byte-identical to today.
114
+ - **Stays global:** `audit_days` (keep-forever — tamper-evident hash chain, ~6-yr HIPAA expectation),
115
+ `state_max_age_days` (per-*namespace*, not per-connection — a separate follow-up),
116
+ `connection_event_retention_hours` (#46; already its own window), and `max_db_mb` / WAL / VACUUM (they
117
+ govern the one store *file*, not a feed).
118
+
119
+ ## Acceptance Criteria
120
+
121
+ > EARS form; each linked (`→`) to its test/fixture. `messagefoundry adr-analyze` checks each `→` resolves.
122
+
123
+ - **AC-1** — WHERE an inbound connection sets `messages_days`, WHEN `run_once` purges message bodies, THE
124
+ SYSTEM SHALL apply that connection's cutoff to rows it received (`messages.channel_id`) and the global
125
+ `[retention].messages_days` cutoff to every connection without an override.
126
+ → `tests/test_per_connection_retention.py::test_override_applies_per_inbound`
127
+ - **AC-2** — WHERE an outbound connection sets `dead_letter_days`, WHEN `run_once` purges dead-letters, THE
128
+ SYSTEM SHALL key the cutoff off the **outbound** that dead-lettered each row (`queue.destination_name`).
129
+ → `tests/test_per_connection_retention.py::test_dead_letter_override_keys_off_outbound`
130
+ - **AC-3** — WHEN no per-connection override is configured, THE SYSTEM SHALL purge exactly as the global
131
+ store-wide policy does today (a single global cutoff; byte-identical behaviour).
132
+ → `tests/test_per_connection_retention.py::test_global_only_unchanged`
133
+ - **AC-4** — IF a message body is still pending/inflight, THEN THE SYSTEM SHALL NOT purge it even when its
134
+ per-connection cutoff has elapsed (the cutoff AND-s with the in-flight guard).
135
+ → `tests/test_per_connection_retention.py::test_in_flight_body_never_purged`
136
+ - **AC-5** — WHEN a per-connection override is set to `0`, THE SYSTEM SHALL keep that connection's bodies
137
+ forever even while the global window prunes others (per-feed opt-out).
138
+ → `tests/test_per_connection_retention.py::test_per_connection_zero_keeps_forever`
139
+ - **AC-6** — WHEN a pass purges across connections, THE SYSTEM SHALL write **exactly one** `retention_purge`
140
+ audit row recording the per-connection cutoffs + counts and **no message content**.
141
+ → `tests/test_per_connection_retention.py::test_audit_records_per_connection_cutoffs`
142
+ - **AC-7** — THE SYSTEM SHALL accept `messages_days` / `dead_letter_days` from both a code-first
143
+ `inbound()`/`outbound()` and a `connections.toml` entry, resolving to identical `InboundConnection` /
144
+ `OutboundConnection` overrides.
145
+ → `tests/test_connections_file.py::test_retention_override_roundtrips_toml`
146
+ - **AC-8** — THE SYSTEM SHALL apply the per-connection cutoff identically on SQLite, Postgres, and SQL
147
+ Server (purge-SQL parity).
148
+ → `tests/test_per_connection_retention.py::test_three_backend_parity`
149
+
150
+ ## Options considered
151
+
152
+ 1. **Per-connection override field on the inbound/outbound spec, reusing the #46 override plumbing —
153
+ CHOSEN.** Adds `messages_days`/`dead_letter_days` (`None` = inherit) to the connection spec exactly as
154
+ `capture_ack`/`retry`/`buildup` already do, threaded through the same `build_*` factories + the same ADR
155
+ 0007 `connections.toml` desugaring, and threads a `{connection → cutoff}` map into the existing purge
156
+ methods + the existing single-pass / single-audit `run_once`. Minimal new surface; one override idiom; the
157
+ keys are already GUI/TOML-editable. Matches BACKLOG #34's stated scope.
158
+ 2. **A new `[retention.connections.<name>]` settings overlay (a parallel resolver).** Rejected: invents a
159
+ *second* override idiom parallel to FIFO/RetryPolicy/BuildupThreshold/#46-diagnostics, splits a
160
+ connection's config across two surfaces, and re-derives a connection→cutoff resolver the #46 work already
161
+ provides. The override belongs *on the connection*, where every other per-connection knob lives — the
162
+ brief's explicit "reuse #46 plumbing, don't invent a parallel one."
163
+ 3. **A `retention` field on the lower-level `Source`/`Destination` model** ([config/models.py](../../messagefoundry/config/models.py)).
164
+ Rejected: those carry transport *type + settings*; the per-connection lifecycle knobs (router binding,
165
+ FIFO, retry, #46 diagnostics) all live on the higher-level `InboundConnection`/`OutboundConnection` spec —
166
+ retention rides there for consistency.
167
+ 4. **A second `RetentionRunner` per connection.** Rejected: retention is a leader-only WRITE singleton
168
+ (PHI-body nulling + audit) that must run on exactly one node and write **one** audit row per pass; N
169
+ runners multiply the audit rows, the leader-election surface, and WAL/VACUUM contention. One runner with a
170
+ per-connection cutoff map is strictly simpler.
171
+ 5. **Status quo (store-wide only).** Rejected: forces a clinically-important feed onto a noisy feed's window
172
+ and blocks feed-by-feed PHI minimization — the explicit owner ask and the Mirth per-channel gap.
173
+
174
+ ## Consequences
175
+
176
+ **Positive** — Operators get the Mirth per-channel lever: keep ADT 90 days, prune a high-volume lab feed at
177
+ 7, opt one feed out entirely — bounding PHI footprint feed-by-feed. It reuses one override idiom (no new
178
+ mental model, no new settings section, no new resolver), extends the existing single pass + single audit row,
179
+ and is purely additive (every default `None` ⇒ today's behaviour).
180
+
181
+ **Negative / risks** — The purge SQL gains a per-connection branch on three backends — a small parity surface
182
+ that must stay in lock-step (covered by AC-8 + the parity test). The per-connection cutoff map is resolved
183
+ each pass from the live registry, so a reload that changes an override takes effect on the next pass (not
184
+ retroactively un-purging already-nulled bodies — the intended one-way trade-off). Per-connection counts in
185
+ the audit detail grow the row with the number of connections that purged in a pass (still metadata-only).
186
+ Mis-keying inbound (`channel_id`) vs outbound (`destination_name`) would purge the wrong rows — the AC-1/AC-2
187
+ split pins it.
188
+
189
+ **Out of scope / stays global** — `audit_days` (keep-forever; tamper-evident chain, HIPAA ~6 yr),
190
+ `state_max_age_days` (per-*namespace* follow-up, not per-connection), `connection_event_retention_hours`
191
+ (#46; already its own window), `max_db_mb` / `wal_checkpoint_seconds` / `vacuum_at` (govern the one store
192
+ file, not a feed). Deleting metadata rows (vs nulling bodies) stays **declined** — count-and-log keeps the
193
+ row forever.
194
+
195
+ ## To resolve on acceptance
196
+
197
+ - [ ] **Map vs join.** Resolve the per-connection cutoff as an in-Python `{connection → older_than}` map
198
+ passed to the purge call, **or** push a `(connection, cutoff)` temp/VALUES join into the purge SQL? (Map is
199
+ simpler and backend-uniform for a handful of overrides; a join scales to many connections. Decide before
200
+ the Postgres / SQL Server parity build.)
201
+ - [ ] **Land-order with the store refactor.** Confirm the purge-SQL change rebases onto the pool-prewarm /
202
+ shared-read-pool store refactor (Lane A is sole store-writer) — coordinate the merge order so neither
203
+ clobbers the other's `store.py` purge methods.
204
+ - [ ] **Leader/audit semantics under sharding.** Confirm the leader-only `run_once` (one owner per process
205
+ today; NullCoordinator single-node) stays correct for per-connection cutoffs under ADR 0037 multi-process
206
+ sharding, where inbounds are partitioned across shards but outbound/logic are shared.
207
+ - [ ] **GUI surfacing.** Confirm the `connections.toml` GUI editor (ADR 0007) renders the two new keys
208
+ (inbound `messages_days`, outbound `dead_letter_days`) — or defer to a follow-up GUI task.