messagefoundry 0.2.7__tar.gz → 0.2.8__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.
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/CHANGELOG.md +42 -1
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/PKG-INFO +1 -1
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/SERVICE.md +19 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/__main__.py +20 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/config/load/_shape.py +21 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/config/load/graph.py +13 -4
- messagefoundry-0.2.8/harness/config/passthrough/graph.py +68 -0
- messagefoundry-0.2.8/harness/config/store_once/graph.py +73 -0
- messagefoundry-0.2.8/harness/load/enginepoll.py +244 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/runner.py +15 -2
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/__init__.py +1 -1
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/__main__.py +8 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/supervisor.py +10 -0
- messagefoundry-0.2.8/tests/test_enginepoll_aggregate.py +152 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_config.py +30 -1
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_report.py +19 -15
- messagefoundry-0.2.8/tests/test_passthrough_graph.py +64 -0
- messagefoundry-0.2.8/tests/test_store_once_graph.py +68 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_supervisor.py +22 -0
- messagefoundry-0.2.7/harness/load/enginepoll.py +0 -162
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.claude/settings.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.dockerignore +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.gitattributes +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/CODEOWNERS +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/SECURITY.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/dependabot.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/benchmark.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/ci.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/cla.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/codeql.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/dependabot-auto-merge.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/dependabot-lock-resync.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/freethread-smoke.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/release-sync-check.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/release.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/scorecard.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/security.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/workflows/vuln-metrics.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.github/zizmor.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.gitignore +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.gitleaks.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.mefor-hooks/pre-commit +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.pre-commit-config.yaml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/.semgrep/messagefoundry.yml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/CLA.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/CLAUDE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/CODE_OF_CONDUCT.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/COMMERCIAL-LICENSE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/CONTRIBUTING.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/GOVERNANCE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/LICENSE +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/MAINTAINERS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/NOTICE +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/Dockerfile +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/compose.yaml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/k8s/secret.example.yaml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/k8s/statefulset.yaml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/locks/requirements-core.lock +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/locks/requirements-sqlserver.lock +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/secrets.env.example +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/smoke/Dockerfile +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/smoke/config/IB_Test_ADT.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docker/smoke/send_adt.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/ADOPTER-CI.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/AI.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/ARCHITECTURE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/BACKLOG.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CI-QUALITY.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CLUSTERING.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CODESETS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CONFIGURATION.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CONNECTIONS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CONTAINER-EXPOSURE-EVALUATION.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CONTRIBUTOR-FIRST-ISSUES.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/CONTRIBUTOR-PROGRAM-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/COUNSEL-ENGAGEMENT-BRIEF.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/DEPLOY-SERVER-DB.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/DEPLOYMENT.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/DICOM.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/DUAL_LICENSING_PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/EARLY-ADOPTER-GUIDE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/FEATURE-MAP.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/HL7-VALIDATION.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/INSTALL-GUIDE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/LOAD-TESTING.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/MENTAL-MODEL.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/MessageFoundry-Mental-Model.docx +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/PHI.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/REMOTE-CONSOLE-CUSTOMER-GUIDE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/REMOTE-CONSOLE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/SECURITY-REMEDIATION-LEDGER.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/SECURITY.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/SUPPORT-POLICY.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/SYSTEM-REQUIREMENTS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/Secure_AI_Development_Standards.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/Secure_Development_Standards.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/TEE-RELAY.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/THROUGHPUT-IMPROVEMENTS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/USER-GUIDE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/WORKTREES.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0001-staged-pipeline-architecture.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0002-phase2-transport-security-and-strong-auth.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0003-non-hl7-transports-database-rest-soap.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0004-payload-agnostic-ingress.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0005-transform-accessible-state.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0006-external-data-lookups.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0007-gui-manageable-connections-toml.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0008-cluster-observability-api.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0009-run-scoped-context-providers.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0010-handler-callable-db-lookup.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0011-timer-scheduled-source.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0012-x12-edi-codec.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0013-increment-2-reingress-design.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0013-query-response-orchestration.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0014-alerting-rules-engine.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0015-ws-soap-outbound-mtls-wssecurity.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0016-synchronous-x12-request-response.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0017-consumer-deployment-model.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0018-per-message-signatures-accepted-risk.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0019-pluggable-keyprovider-hsm-kms-vault.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0020-protocol-diagnostic-capture.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0021-inbound-ack-nak-capture-response-sent.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0022-fhir-resource-codec-rest-client.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0024-smart-backend-services-token-provider.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0025-dicom-codec-store-connectors.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0026-off-box-egress-update-check.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0028-base64-binary-carriage-codec.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0030-anonymization-test-harness-tee.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0031-startup-connection-fault-isolation.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0032-console-desktop-launch.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0033-gui-manageable-code-sets.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0034-static-analysis-triage-policy-accepted-risk-register.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0035-ide-extension-workspace-trust-and-scope.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0036-windows-config-source-trust.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0037-multi-process-sharding-l3.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0038-internal-pass-through-connector.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0039-database-tier-sharding-l5.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0040-free-threaded-engine-support.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/0041-load-path-attestation-and-change-attribution.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/adr/TEMPLATE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-components.png +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-components.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-config-graph.png +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-config-graph.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-diagram.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-message-flow.png +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-message-flow.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-topology.png +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/architecture-topology.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/TUNING-BASELINE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/results/2026-06-16-ci-linux/environment.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/results/2026-06-16-ci-linux/failover-postgres.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/results/2026-06-16-ci-linux/failover-sqlserver.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/results/2026-06-16-ci-linux/reference-postgres.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/results/2026-06-16-ci-linux/reference-sqlite.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/results/2026-06-16-ci-linux/reference-sqlserver.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/benchmarks/step-b-write-amplification.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/design/dbshard.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/design/freethread.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/design/multiproc.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/hl7-message-ordering-reference.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/message-ordering-design.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/ASVS-OPTION-A-MULTISESSION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/ASVS-PARTIALS-SWEEP-MULTISESSION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/DOGFOOD-BACKLOG-MULTISESSION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/MULTISESSION-PLAN-3.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/MULTISESSION-PLAN-v0.2.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/MULTISESSION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/PLAN-3-LANE-HANDOFFS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/V0.2-LANE-HANDOFFS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/v0.1-EXECUTION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/v0.1-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/releases/v0.1.0-PRETAG-CHECKLIST.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/research/cloud-deployment-research-2026-06.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/research/config-ux-review.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/research/non-hl7-transform-components.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/reviews/DEPENDENCY-INFOSEC-POSTURE-2026-06-23.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/reviews/FULL-REVIEW-2026-06-10.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/ADVISORY-PROCESS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/ASVS-FAILS-REMEDIATION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/ASVS-L2-PHASE0-CHANGES.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/ASVS-L2-REMEDIATION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/ASVS-L3-ASSESSMENT.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/ASVS-L3-REMEDIATION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/ASVS-L3-STATUS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/BEYOND-ASVS-L3-ONEPAGE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/BEYOND-ASVS-L3-REMEDIATION-PLAN-ONEPAGE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/BEYOND-ASVS-L3-REMEDIATION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/BEYOND-ASVS-L3.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/DEP-CVE-RUNBOOK.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/DEPENDENCY-METRICS.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/MEFOR-Code-Review-Checklist.xlsx +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/PHASE-8C-RBAC.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/PUBLISHING.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/RCA-TEMPLATE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/RELEASE-GATE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/REMEDIATION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/REVIEW-2026-06-07.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/SDS-CONFORMANCE-REVIEW-2026-06-12.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/SDS-REMEDIATION-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/SECURITY-POSTURE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/SOUP-DEPENDENCY-HANDLING.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/SOUP-REVIEW-2026-06-18.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/SOUP-REVIEW-PROCEDURE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/security/THREAT-MODEL.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/testing/VERIFY.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/testing/WIN2025-ACCEPTANCE.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/testing/WIN2025-TEST-MATRIX.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/docs/testing/WIN2025-TEST-PLAN.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/environments/dev.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/environments/prod.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/acceptance/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/acceptance/__main__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/acceptance/matrix.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/acceptance/probes.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/acceptance/report.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/acceptance/runner.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/compose.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/config/coverage.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/file_panel.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/file_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/corpus.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/correlator.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/failover.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/failover_track.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/governor.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/ids.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/metrics.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profile.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/adt-fanout-stress.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/closed-loop.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/failover.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/fanout-baseline.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/malformed-load.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/reference.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/smoke-sqlserver.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/smoke.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/soak.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/spike-burst.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/sustained-overload.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/profiles/writeamp.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/report.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/sender.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/load/sink.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/mllp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/monitor.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/receive.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/reconcile/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/reconcile/__main__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/reconcile/capture.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/reconcile/compare.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/reconcile/normalize.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/reconcile/report.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/scenarios.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/send.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/harness/window.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/.gitignore +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/.vscodeignore +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/esbuild.js +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/media/hl7schema.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/media/icon-amber.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/media/icon.png +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/media/icon.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/package-lock.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/package.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/snippets/messagefoundry.code-snippets +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/aiPolicy.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/alertEditor.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/auth.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/chat.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/cli.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/codeSetEditor.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/codesetsTree.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/completion.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/connectionEditor.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/editorToolbar.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/engineClient.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/engineTarget.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/extension.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/generate.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/git.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/graphTree.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/home.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/insertElement.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/newRoute.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/promote.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/promoteTarget.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/sourceControl.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/runTest.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/ai-policy.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/chat.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/editor-toolbar.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/engine-target.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/extension.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/index.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/insert-element.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/promote-target.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/pythonpath.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/test/suite/settings-scope.test.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/testBench.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/src/validate.ts +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/tsconfig.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/ide/tsconfig.test.json +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/mefor.code-workspace +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/adr_analyze.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/anon/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/anon/_pools.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/anon/hl7.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/anon/keying.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/anon/leak.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/anon/rules.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/anon/surrogates.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/app.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/approvals.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/auth_models.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/auth_routes.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/field_authz.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/metrics.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/models.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/security.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/api/tls.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/data/common_passwords.NOTICE +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/data/common_passwords.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/identity.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/ldap.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/notifications.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/passwords.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/permissions.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/policy.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/ratelimit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/service.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/tokens.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/auth/totp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/checks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/active_environment.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/ai_policy.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/alerts_edit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/code_sets.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/codeset_edit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/connections_edit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/connections_file.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/db_lookup.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/environments.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/fingerprint.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/ingest_time.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/models.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/reference.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/response.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/run_context.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/settings.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/state.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/tls_policy.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/config/wiring.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/__main__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/_async.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/alerts_page.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/change_password.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/client.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/connections.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/dead_letters_page.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/delegates.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/event_log_page.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/icons/alerts.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/icons/connections.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/icons/dead-letters.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/icons/engine-status.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/icons/log-search.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/icons/logo-lockup.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/icons/users.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/login.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/mfa.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/reauth.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/resources/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/resources/app.ico +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/resources/app.svg +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/search.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/service_control.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/sessions.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/shards.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/shell.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/status.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/theme.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/users_page.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/console/widgets.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/_core.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/_hl7data.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/adt.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/all_types.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/bar.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/dft.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/documents.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/mdm.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/mfn.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/oml.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/orl.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/orm.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/oru.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/ras.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/rde.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/siu.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/generators/vxu.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/hl7schema.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/last_resort.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/logging_setup.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/binary.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/consistency.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/dicom/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/dicom/_deps.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/dicom/_util.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/dicom/dataset.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/dicom/errors.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/dicom/hl7_map.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/dicom/peek.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/fhir/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/fhir/_deps.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/fhir/errors.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/fhir/peek.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/fhir/resource.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/groups.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/message.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/peek.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/split.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/summary.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/tree.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/validate.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/x12/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/x12/delimiters.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/x12/errors.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/x12/interchange.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/x12/message.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/parsing/x12/peek.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/alert_sinks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/alerts.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/cert_expiry.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/cluster.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/cluster_sqlserver.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/config_convergence.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/dryrun.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/engine.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/leader_tasks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/reference_sync.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/retention.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/security_notify.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/sharding.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/state_convergence.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/pipeline/wiring_runner.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/py.typed +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/redaction.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/scaffold.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/secrets_dpapi.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/audit_tee.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/base.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/crypto.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/keyprovider.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/postgres.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/sqlserver.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/store/store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/timezone.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/base.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/database.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/dicom.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/dicomweb.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/fhir.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/file.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/framing.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/loopback.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/mllp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/passthrough.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/remotefile.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/rest.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/signing.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/smart.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/soap.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/tcp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/timer.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/transports/x12.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/verify/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/verify/checks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/verify/model.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/verify/report.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/verify/runner.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/messagefoundry/verify/smoke.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/packaging/messagefoundry-harness/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/packaging/messagefoundry-harness/pyproject.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/pyproject.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/requirements.lock +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/IB_ACME_ADT.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/IB_FHIR_INTAKE.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/IB_IMMUNIZATION_VXU.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/IB_PARTNER_X12.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/IB_RADIOLOGY_SR.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/IB_RTE_ELIGIBILITY.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/adt.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/codesets/event_labels.csv +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/codesets/facility_mnemonics.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/config/connections.toml +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/consistency/validated_adt.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/dicom/generate_sr_sample.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/adt_a01.hl7 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/adt_batch.hl7 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/.gitattributes +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/adt_a01.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/adt_a03.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/batch_18_messages.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/erp_z99_v231.hl7 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/omd_o03.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/omd_o03_rep.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/hapi-hl7v2/oml_o21.hl7 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/messages/x12_270_eligibility.edi +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/results_relay/README.md +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/results_relay/codesets/test_codes.csv +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/results_relay/messages/oru_all_cancelled.hl7 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/results_relay/messages/oru_results.hl7 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/results_relay/results_relay.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/samples/send_mllp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/console/install-console-shortcut.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/console/pack_ico.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/console/uninstall-console-shortcut.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/dev/postgres.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/dev/sqlserver-docker.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/dev/sqlserver.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/hooks/block-blanket-git-stage.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/publish/check_release_sync.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/publish/publish-denylist.txt +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/publish/publish.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/publish/scan_forbidden.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/security/crypto_inventory_check.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/security/vuln_metrics.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/service/import-db-ca.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/service/install-service.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/service/uninstall-service.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/trace_icon.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/worktree/new.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/worktree/remove.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/worktree/session-context.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/scripts/worktree/spawn.ps1 +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/__main__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/__init__.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/_hl7data.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/_pools.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/hl7.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/keying.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/leak.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/rules.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/anon/surrogates.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/compare.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/correlate.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/hl7_fields.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/mefor_api.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/mllp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/relay.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/report.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tee/store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/_dicom_sample.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/_failover_load_support.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/_fhir_fixtures.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/conftest.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_acceptance_framework.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ack_capture_runner.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ack_sent_store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_active_environment.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ad_group_scope.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_admin_new_ip.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_adr_analyze.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ai_policy.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_alert_rules.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_alert_sinks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_alerts_edit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_alerts_rules_api.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_anon_core.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_anon_integration.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_anon_parity.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_api.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_api_auth.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_api_reload.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_api_tls.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_approvals.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_asvs_phase0.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_audit_integrity.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_audit_offbox_tee.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_auth_core.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_auth_entry_hardening.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_auth_hardening.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_auth_service.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_auth_session_lifecycle.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_auth_store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_binary_carriage.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_bootstrap_admin_perms.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_cert_expiry.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_channel_rbac.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_checks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_checks_lint.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_cli.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_cluster.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_cluster_failover_postgres.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_cluster_failover_sqlserver.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_cluster_graph_gating.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_cluster_lease.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_code_sets.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_codeset_edit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_config_fingerprint.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_config_source_trust.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connection_api.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connection_event_api.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connection_event_emit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connection_event_outbound.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connection_event_scope.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connection_event_store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connection_resilience.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connections_cli.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_connections_file.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_consistency.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_alerts.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_auth.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_client.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_dead_letters.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_event_log.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_hardening.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_icon.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_password.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_sessions.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_shards.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_status.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_step_up.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_theme.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_users.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_console_widgets.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_database_connector_integration.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_database_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_db_lookup.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_db_lookup_live_runner.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_delivery_settings.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dependabot_automerge_guardrails.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dependency_boundaries.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dicom_codec.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dicom_scp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dicom_scp_security.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dicom_scu.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dicom_wiring.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dicomweb.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_docs_runbooks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_dryrun.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ed_documents.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ed_documents_e2e.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_egress_allowlist.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_environments.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_fhir_parsing.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_fhir_resource.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_fhir_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_field_authz.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_field_authz_metadata.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_fifo_ordering.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_generate_cli.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_generated_adt.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_generators_core.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_generators_types.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_groups.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_harness.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_harness_compose.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_harness_config.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_harness_faults.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_harness_file.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_harness_monitor.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_harness_scenarios.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_hl7_core_features.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_hl7schema.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_inbound_bind.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ingest_time.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_keyprovider.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_last_admin_guard.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_last_resort.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_leader_tasks.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_listener_tls_exposure.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_corpus.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_failover_postgres.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_failover_sqlserver.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_failover_unit.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_metrics.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_profile.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_runner.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_sender.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_load_sink.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_logging.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_message.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_message_split.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_metrics_exporter.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_mfa.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_mllp_encoding_override.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_mllp_tls.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_nonhl7_ingress_size_cap.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_operability_config.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_outbound_signing.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_outbound_simulate.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_packaging.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_parse_tree.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_parsing.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_passthrough.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_payload_agnostic_ingress.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_postgres_store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_reconcile_capture.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_reconcile_compare.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_reconcile_harness.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_redaction.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_reference_sets.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_reingress.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_remotefile_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_response_capture.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_rest_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_retention.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_run_context.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_scaffold.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_scaffold_requirements.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_scan_forbidden.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_secrets_dpapi.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_security_notify.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_security_static.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_service_control.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_settings.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_sharding.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_sibling_helper_finder.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_smart_backend.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_soap_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_soap_wssecurity.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_sqlserver_coordinator.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_sqlserver_cursor_close.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_sqlserver_schema_init.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_sqlserver_store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_staged_pipeline.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_startup_fault_isolation.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_stats_reset.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_step_up.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_store_backend.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_store_encryption.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_store_file_hardening.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_store_once_deliver_many.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_store_read_pool.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_store_ssl.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_summary.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_task_resilience.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tcp_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_cli.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_compare.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_correlate.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_hl7_fields.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_mefor_api.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_mllp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_relay.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_report.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tee_store.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_timer_source.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_timezone.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_tls_policy.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_totp.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_totp_window.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_transform_offloop.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_transform_state.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_transports.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_verify.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_version.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_win2025_acceptance.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_wiring.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_wiring_engine.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_wiring_reload.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_wiring_serve.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_ws_stats_revalidation.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_x12_parsing.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_x12_rte.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_x12_source_ip_allowlist.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/tests/test_x12_transport.py +0 -0
- {messagefoundry-0.2.7 → messagefoundry-0.2.8}/uv.lock +0 -0
|
@@ -6,6 +6,46 @@ All notable changes to MessageFoundry are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.8] — 2026-06-27 — Early Access
|
|
10
|
+
|
|
11
|
+
A tooling/ops release: the load harness gains a **multi-shard driver** so one harness can drive a
|
|
12
|
+
`supervise` cluster (unblocking the multi-core throughput measurement), `supervise` resolves
|
|
13
|
+
`--env` files for its shards, and a prominent upgrade note for the config-directory permission
|
|
14
|
+
guard introduced in 0.2.6.
|
|
15
|
+
|
|
16
|
+
> ### ⚠ Upgrading from ≤ 0.2.5 — tighten config-dir ACLs first
|
|
17
|
+
> The config-directory permission guard (SEC-003 / ADR 0036), added in **0.2.6**, refuses to load a
|
|
18
|
+
> `--config` directory that is **writable by a broad principal** (e.g. `Authenticated Users` /
|
|
19
|
+
> `S-1-5-11`). A deployment whose config dir inherits that write — common under `C:\srv\…` — will
|
|
20
|
+
> **fail to start on first upgrade to ≥ 0.2.6** with *"refusing to load config from writable-by-others
|
|
21
|
+
> path …"*. **Before upgrading**, tighten the directory (elevated):
|
|
22
|
+
> ```powershell
|
|
23
|
+
> icacls "<config-dir>" /inheritance:d /T
|
|
24
|
+
> icacls "<config-dir>" /remove:g *S-1-5-11 /T # drop Authenticated Users
|
|
25
|
+
> icacls "<config-dir>" /grant *S-1-5-18:(OI)(CI)F /grant *S-1-5-32-544:(OI)(CI)F /T # SYSTEM + Admins
|
|
26
|
+
> ```
|
|
27
|
+
> See [`docs/SERVICE.md`](docs/SERVICE.md) → *Update to a new build* and *Lock down the config
|
|
28
|
+
> directory (CONFIG-2)*.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Multi-shard load driving (`messagefoundry-harness`).** `python -m harness` gains
|
|
32
|
+
**`--skip-preflight`** (drive shard MLLP ports that no single `--engine` owns) and a repeatable
|
|
33
|
+
**`--shard-engine <url>`**: the engine poller now takes a list of shard APIs and **sums** each
|
|
34
|
+
shard's `/stats` (read/written/backlog/in_pipeline/queue_depth/dead) into one cluster sample, so
|
|
35
|
+
the no-loss reconcile and drain are **cluster-aggregate** — a healthy K-shard run reports pass,
|
|
36
|
+
not a false "lost on intake". With no `--shard-engine` the behavior is byte-identical to before.
|
|
37
|
+
Two sample graphs ship for the throughput suite: `harness/config/store_once` (the
|
|
38
|
+
dedup-triggering one-handler-`list[Send]`-of-identical-body shape for store-once) and
|
|
39
|
+
`harness/config/passthrough` (an internal `PassThrough()` re-ingress hop); the load graph
|
|
40
|
+
(`harness/config/load`) is now shard-taggable via `MEFOR_LOAD_SHARD_ADT`/`_RESULTS`/`_OTHER`. (#604)
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- **`supervise --project-root`.** `supervise` now accepts `--project-root` and forwards it to each
|
|
44
|
+
spawned `serve --shard`, so `supervise --config <dir> --env <env>` resolves each shard's
|
|
45
|
+
`environments/<env>.toml` (previously the shards resolved nothing from their spawned cwd and
|
|
46
|
+
required an explicit `--service-config` posture). Backward compatible — no `--project-root` is
|
|
47
|
+
unchanged. (#602)
|
|
48
|
+
|
|
9
49
|
## [0.2.7] — 2026-06-27 — Early Access
|
|
10
50
|
|
|
11
51
|
A docs/packaging release that fixes the broken badge images on the PyPI project page
|
|
@@ -299,7 +339,8 @@ tests, but the external code review + penetration test (the bar for a security-c
|
|
|
299
339
|
- Releases are built, SBOM'd (CycloneDX), and signed with [Sigstore](https://www.sigstore.dev/) — see the
|
|
300
340
|
`release` workflow.
|
|
301
341
|
|
|
302
|
-
[Unreleased]: https://github.com/wshallwshall/MessageFoundry/compare/v0.2.
|
|
342
|
+
[Unreleased]: https://github.com/wshallwshall/MessageFoundry/compare/v0.2.8...HEAD
|
|
343
|
+
[0.2.8]: https://github.com/wshallwshall/MessageFoundry/compare/v0.2.7...v0.2.8
|
|
303
344
|
[0.2.7]: https://github.com/wshallwshall/MessageFoundry/compare/v0.2.6...v0.2.7
|
|
304
345
|
[0.2.6]: https://github.com/wshallwshall/MessageFoundry/compare/v0.2.5...v0.2.6
|
|
305
346
|
[0.2.5]: https://github.com/wshallwshall/MessageFoundry/compare/v0.2.4...v0.2.5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: messagefoundry
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
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/
|
|
@@ -91,6 +91,16 @@ definition drifted — the install script is idempotent (it stops and reconfigur
|
|
|
91
91
|
If the package was installed **non-editable** (a plain `pip install .`), the venv holds a
|
|
92
92
|
snapshot of the old code — run `.venv\Scripts\python.exe -m pip install -e .` first, then restart.
|
|
93
93
|
|
|
94
|
+
> **⚠ Upgrading from ≤ 0.2.5 → ≥ 0.2.6: tighten the config-dir ACLs first.** The config-directory
|
|
95
|
+
> permission guard (SEC-003 / ADR 0036) did **not** exist in 0.2.5. From 0.2.6 on, `serve` refuses to
|
|
96
|
+
> start against a `--config` directory **writable by a broad principal** (e.g. `Authenticated Users` /
|
|
97
|
+
> `S-1-5-11`) — *"refusing to load config from writable-by-others path …"*. A config dir that inherits
|
|
98
|
+
> that write (common under `C:\srv\…`) therefore **fails its first start after the upgrade**. Lock it
|
|
99
|
+
> down **before** restarting onto the new build — use the surgical recipe under
|
|
100
|
+
> [Lock down the config directory (CONFIG-2)](#lock-down-the-config-directory-config-2)
|
|
101
|
+
> (`icacls /inheritance:d /T` + `/remove:g *S-1-5-11 /T` + grant SYSTEM/Admins), the lighter-touch
|
|
102
|
+
> alternative to a full `/inheritance:r` reset for a shared tree.
|
|
103
|
+
|
|
94
104
|
## Start / stop / status
|
|
95
105
|
|
|
96
106
|
```powershell
|
|
@@ -190,6 +200,15 @@ trust boundary: anyone who can write a `.py` file there can run code as the serv
|
|
|
190
200
|
(full) and the service account (read+execute). It is **opt-in** because the config dir often lives
|
|
191
201
|
inside a developer's repo where stripping inheritance is surprising — for production, point
|
|
192
202
|
`-Config` at a dedicated admin-owned directory and pass `-LockConfigDir`.
|
|
203
|
+
- **Fix an existing tree that inherits a broad write grant** without a full ACL reset. A config dir
|
|
204
|
+
placed under a shared root (e.g. `C:\srv\…`) often inherits `Authenticated Users` (`S-1-5-11`)
|
|
205
|
+
write, which trips the guard below. The lighter-touch alternative to `/inheritance:r` is to break
|
|
206
|
+
inheritance, surgically drop just the broad principal, and grant the run-as user read+execute:
|
|
207
|
+
```powershell
|
|
208
|
+
icacls "C:\srv\mefor\config" /inheritance:d /T
|
|
209
|
+
icacls "C:\srv\mefor\config" /remove:g *S-1-5-11 /T
|
|
210
|
+
icacls "C:\srv\mefor\config" /grant "<run-as-user>:(OI)(CI)RX" /T
|
|
211
|
+
```
|
|
193
212
|
- The loader **actively enforces** this at load time (and on `/config/reload`), not just as a
|
|
194
213
|
documented recommendation (ADR 0036, SEC-003):
|
|
195
214
|
- On **Windows** the loader now parses the directory's and each `*.py`'s NTFS owner + DACL and
|
|
@@ -69,6 +69,24 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
69
69
|
"--sink-port", type=int, default=2700, help="load: base correlation-sink port"
|
|
70
70
|
)
|
|
71
71
|
parser.add_argument("--sink-ports", type=int, default=1, help="load: contiguous sink ports")
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"--skip-preflight",
|
|
74
|
+
action="store_true",
|
|
75
|
+
help="load: skip the 'engine serves all target ports' check — for driving a `supervise` "
|
|
76
|
+
"multi-shard cluster from one harness (the MLLP ports are spread across the shard engines, "
|
|
77
|
+
"so no single --engine serves them all). Point every shard's MEFOR_LOAD_SINK_PORT at this "
|
|
78
|
+
"run's --sink-port so the one correlation sink aggregates all shards' end-to-end throughput.",
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"--shard-engine",
|
|
82
|
+
action="append",
|
|
83
|
+
metavar="URL",
|
|
84
|
+
help="load: an EXTRA engine API base URL to poll + aggregate alongside --engine (repeatable). "
|
|
85
|
+
"Drives a `supervise` multi-shard cluster: pass --engine for the primary shard and one "
|
|
86
|
+
"--shard-engine per other shard, and the harness sums every shard's /stats so the no-loss "
|
|
87
|
+
"reconcile + drain see true cluster totals. Pair with --skip-preflight (no one engine serves "
|
|
88
|
+
"all MLLP ports). With none given the single --engine is polled exactly as before.",
|
|
89
|
+
)
|
|
72
90
|
parser.add_argument("--report-json", help="load: write the JSON report to this path")
|
|
73
91
|
parser.add_argument("--report-csv", help="load: write the per-phase CSV to this path")
|
|
74
92
|
parser.add_argument("--baseline", help="load: compare against this saved JSON report")
|
|
@@ -166,6 +184,8 @@ def _run_load(args: argparse.Namespace) -> int:
|
|
|
166
184
|
sink_port=args.sink_port,
|
|
167
185
|
sink_ports=args.sink_ports,
|
|
168
186
|
db_backend=args.db_backend,
|
|
187
|
+
skip_preflight=args.skip_preflight,
|
|
188
|
+
shard_engines=tuple(args.shard_engine or ()),
|
|
169
189
|
)
|
|
170
190
|
)
|
|
171
191
|
except PreflightError as exc:
|
|
@@ -18,6 +18,14 @@ Knobs (all optional, with safe defaults so ``serve`` works with none set):
|
|
|
18
18
|
* ``MEFOR_LOAD_ADT_PORT`` — ADT hub inbound MLLP port (default 2600).
|
|
19
19
|
* ``MEFOR_LOAD_RESULTS_PORT`` — results hub inbound MLLP port (default 2601).
|
|
20
20
|
* ``MEFOR_LOAD_OTHER_PORT`` — other hub inbound MLLP port (default 2602).
|
|
21
|
+
* ``MEFOR_LOAD_SHARD_ADT`` — ``supervise`` shard id for the ADT hub (default unset → no tag).
|
|
22
|
+
* ``MEFOR_LOAD_SHARD_RESULTS`` — ``supervise`` shard id for the results hub (default unset → no tag).
|
|
23
|
+
* ``MEFOR_LOAD_SHARD_OTHER`` — ``supervise`` shard id for the other hub (default unset → no tag).
|
|
24
|
+
|
|
25
|
+
Shards (all optional): tagging a hub with ``shard=`` routes it to a named ``messagefoundry supervise``
|
|
26
|
+
subprocess. **Unset (the default) = no tag = a single implicit shard**, so the SAME load graph serves
|
|
27
|
+
both unsharded (default) and sharded (e.g. ``MEFOR_LOAD_SHARD_ADT=a`` / ``_RESULTS=b`` / ``_OTHER=b``
|
|
28
|
+
→ a 2-shard layout) with no other change. The tags never affect routing.
|
|
21
29
|
|
|
22
30
|
The graph is **synthetic and generic** — it models the *shape* of a high-fan-out estate (one big ADT
|
|
23
31
|
hub plus results/orders hubs), never a real site. See ``docs/LOAD-TESTING.md``.
|
|
@@ -64,6 +72,13 @@ def _env_float(name: str, default: float, *, minimum: float = 0.0) -> float:
|
|
|
64
72
|
return value
|
|
65
73
|
|
|
66
74
|
|
|
75
|
+
def _env_shard(name: str) -> str | None:
|
|
76
|
+
"""A shard id from the environment, or ``None`` when unset/blank (= no shard tag)."""
|
|
77
|
+
raw = os.environ.get(name)
|
|
78
|
+
raw = raw.strip() if raw else ""
|
|
79
|
+
return raw or None
|
|
80
|
+
|
|
81
|
+
|
|
67
82
|
@dataclass(frozen=True)
|
|
68
83
|
class Shape:
|
|
69
84
|
"""Resolved load-graph parameters (read once from the environment at load time)."""
|
|
@@ -78,6 +93,9 @@ class Shape:
|
|
|
78
93
|
adt_port: int
|
|
79
94
|
results_port: int
|
|
80
95
|
other_port: int
|
|
96
|
+
shard_adt: str | None
|
|
97
|
+
shard_results: str | None
|
|
98
|
+
shard_other: str | None
|
|
81
99
|
|
|
82
100
|
def sink_endpoint(self, index: int) -> tuple[str, int]:
|
|
83
101
|
"""Round-robin a destination index across the contiguous sink port range."""
|
|
@@ -101,6 +119,9 @@ def load_shape() -> Shape:
|
|
|
101
119
|
adt_port=_env_int("MEFOR_LOAD_ADT_PORT", 2600, minimum=1),
|
|
102
120
|
results_port=_env_int("MEFOR_LOAD_RESULTS_PORT", 2601, minimum=1),
|
|
103
121
|
other_port=_env_int("MEFOR_LOAD_OTHER_PORT", 2602, minimum=1),
|
|
122
|
+
shard_adt=_env_shard("MEFOR_LOAD_SHARD_ADT"),
|
|
123
|
+
shard_results=_env_shard("MEFOR_LOAD_SHARD_RESULTS"),
|
|
124
|
+
shard_other=_env_shard("MEFOR_LOAD_SHARD_OTHER"),
|
|
104
125
|
)
|
|
105
126
|
|
|
106
127
|
|
|
@@ -69,10 +69,19 @@ _OTH_HANDLERS = _register_lane("OTH", _SHAPE.results_fanout, _SHAPE)
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
# Three inbound MLLP hubs matching the load profiles' target ports. Each fans every received message
|
|
72
|
-
# to its lane's full handler set (the sender sends only the matching types to each port).
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
inbound("
|
|
72
|
+
# to its lane's full handler set (the sender sends only the matching types to each port). Each hub may
|
|
73
|
+
# be tagged to a `supervise` shard via MEFOR_LOAD_SHARD_* (default unset → shard=None → no tag → a
|
|
74
|
+
# single implicit shard = byte-identical to the unsharded graph); see _shape.
|
|
75
|
+
inbound("IB_Load_ADT", MLLP(port=_SHAPE.adt_port), router="adt_router", shard=_SHAPE.shard_adt)
|
|
76
|
+
inbound(
|
|
77
|
+
"IB_Load_Results",
|
|
78
|
+
MLLP(port=_SHAPE.results_port),
|
|
79
|
+
router="results_router",
|
|
80
|
+
shard=_SHAPE.shard_results,
|
|
81
|
+
)
|
|
82
|
+
inbound(
|
|
83
|
+
"IB_Load_Other", MLLP(port=_SHAPE.other_port), router="other_router", shard=_SHAPE.shard_other
|
|
84
|
+
)
|
|
76
85
|
|
|
77
86
|
|
|
78
87
|
@router("adt_router")
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
# Copyright (C) 2026 MessageFoundry Organization and contributors
|
|
3
|
+
"""Pass-through (PT) re-ingress system-under-test (§7 S7.4/S7.5).
|
|
4
|
+
|
|
5
|
+
A minimal graph exercising the ADR 0013 (generalized) **pass-through** primitive: an MLLP entry hub
|
|
6
|
+
routes every message to a handler that ``Send``\\ s it *into* an internal :func:`PassThrough` inbound
|
|
7
|
+
(``PT_Relay``) — naming it like an outbound. The engine re-ingresses that body as a new, independent
|
|
8
|
+
inbound message on ``PT_Relay``, whose **own** router/handler then forward it to the real outbound
|
|
9
|
+
(the harness correlation sink). So one logical feed crosses an internal hop before delivery, with no
|
|
10
|
+
external round-trip — the shape the PT re-ingress throughput rows measure.
|
|
11
|
+
|
|
12
|
+
Synthetic + generic; reuses the load graph's ``_shape`` for the entry port and sink endpoint, so
|
|
13
|
+
``MEFOR_LOAD_ADT_PORT`` / ``MEFOR_LOAD_SINK_PORT`` behave as in ``harness/config/load``. Serve it::
|
|
14
|
+
|
|
15
|
+
MEFOR_LOAD_ADT_PORT=2600 MEFOR_LOAD_SINK_PORT=2700 \
|
|
16
|
+
python -m messagefoundry serve --config harness/config/passthrough --db ./pt.db
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from messagefoundry import MLLP, PassThrough, Send, handler, inbound, outbound, router
|
|
22
|
+
from messagefoundry.config.models import RetryPolicy
|
|
23
|
+
from messagefoundry.parsing.message import Message, RawMessage
|
|
24
|
+
|
|
25
|
+
from harness.config.load._shape import load_shape
|
|
26
|
+
|
|
27
|
+
_SHAPE = load_shape()
|
|
28
|
+
|
|
29
|
+
_RETRY = RetryPolicy(
|
|
30
|
+
max_attempts=5, backoff_seconds=0.5, backoff_multiplier=2.0, max_backoff_seconds=5.0
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# The real egress: one outbound delivering to the harness correlation sink.
|
|
34
|
+
_SINK_HOST, _SINK_PORT = _SHAPE.sink_endpoint(0)
|
|
35
|
+
outbound(
|
|
36
|
+
"OB_PT_Sink",
|
|
37
|
+
MLLP(host=_SINK_HOST, port=_SINK_PORT, connect_timeout=2.0, timeout_seconds=5.0),
|
|
38
|
+
retry=_RETRY,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# The entry hub: an external MLLP inbound whose handler hands every message off to the PT inbound.
|
|
42
|
+
inbound("IB_PT_Entry", MLLP(port=_SHAPE.adt_port), router="pt_entry_router")
|
|
43
|
+
|
|
44
|
+
# The internal pass-through inbound: no socket; fed only by the Send-into-PT handoff below. Its own
|
|
45
|
+
# router/handler re-route the re-ingressed body to the real sink outbound.
|
|
46
|
+
inbound("PT_Relay", PassThrough(), router="pt_relay_router")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@router("pt_entry_router")
|
|
50
|
+
def route_entry(msg: Message | RawMessage) -> list[str]:
|
|
51
|
+
return ["pt_entry_handler"]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@handler("pt_entry_handler")
|
|
55
|
+
def to_passthrough(msg: Message | RawMessage) -> Send:
|
|
56
|
+
# Send INTO the PT inbound (named like an outbound) → the engine re-ingresses it on PT_Relay.
|
|
57
|
+
return Send("PT_Relay", msg)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@router("pt_relay_router")
|
|
61
|
+
def route_relay(msg: Message | RawMessage) -> list[str]:
|
|
62
|
+
return ["pt_relay_handler"]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@handler("pt_relay_handler")
|
|
66
|
+
def to_sink(msg: Message | RawMessage) -> Send:
|
|
67
|
+
# The PT inbound's own handler forwards the re-ingressed body to the real outbound.
|
|
68
|
+
return Send("OB_PT_Sink", msg)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
# Copyright (C) 2026 MessageFoundry Organization and contributors
|
|
3
|
+
"""Store-once-deliver-many (L2b) system-under-test — the shape that actually triggers dedup.
|
|
4
|
+
|
|
5
|
+
The load graph (``harness/config/load``) fans out via N **separate** handlers (one ``Send`` each → N
|
|
6
|
+
``transform_handoff``s, each a single delivery → the body is stored **inline**), and its ``edit``
|
|
7
|
+
transform rewrites MSH-6 *per destination* → N **distinct** bodies. So the load graph never exercises
|
|
8
|
+
store-once-deliver-many.
|
|
9
|
+
|
|
10
|
+
This graph fans out via **one** handler returning ``list[Send]`` of the **identical** body to N
|
|
11
|
+
destinations — a single ``transform_handoff`` with N deliveries — which is exactly the shape that
|
|
12
|
+
triggers L2b: the body is content-addressed and written **once** to ``shared_body``, referenced by N
|
|
13
|
+
``queue.body_ref`` rows (instead of N inline copies). Serve it for §7 **J1/S7.1** (store-once
|
|
14
|
+
functional) and **J9/S7.6** (write-amplification)::
|
|
15
|
+
|
|
16
|
+
MEFOR_LOAD_FANOUT=20 MEFOR_LOAD_SINK_PORT=2700 \
|
|
17
|
+
python -m messagefoundry serve --config harness/config/store_once --db ./store_once.db
|
|
18
|
+
|
|
19
|
+
then inject a few ADT messages on the inbound port and inspect the store (``shared_body`` row count,
|
|
20
|
+
``queue.body_ref``). Synthetic + generic; reuses the load graph's ``_shape`` for ports/sink/fan-out so
|
|
21
|
+
``MEFOR_LOAD_FANOUT`` / ``MEFOR_LOAD_SINK_PORT`` / ``MEFOR_LOAD_ADT_PORT`` behave the same as there.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from messagefoundry import MLLP, Send, handler, inbound, outbound, router
|
|
27
|
+
from messagefoundry.config.models import RetryPolicy
|
|
28
|
+
from messagefoundry.parsing.message import Message, RawMessage
|
|
29
|
+
|
|
30
|
+
from harness.config.load._shape import load_shape
|
|
31
|
+
|
|
32
|
+
_SHAPE = load_shape()
|
|
33
|
+
|
|
34
|
+
# A few attempts with brief backoff (the sink always AA's, so retries shouldn't fire) — a transient
|
|
35
|
+
# hiccup rides out rather than dead-lettering and dirtying the no-loss / store-once inspection.
|
|
36
|
+
_RETRY = RetryPolicy(
|
|
37
|
+
max_attempts=5, backoff_seconds=0.5, backoff_multiplier=2.0, max_backoff_seconds=5.0
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _register_dests(fanout: int) -> list[str]:
|
|
42
|
+
"""Declare ``fanout`` outbound destinations, all delivering to the harness correlation sink."""
|
|
43
|
+
names: list[str] = []
|
|
44
|
+
for i in range(fanout):
|
|
45
|
+
dest = f"OB_StoreOnce_{i:02d}"
|
|
46
|
+
host, port = _SHAPE.sink_endpoint(i)
|
|
47
|
+
outbound(
|
|
48
|
+
dest,
|
|
49
|
+
MLLP(host=host, port=port, connect_timeout=2.0, timeout_seconds=5.0),
|
|
50
|
+
retry=_RETRY,
|
|
51
|
+
)
|
|
52
|
+
names.append(dest)
|
|
53
|
+
return names
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
_DESTS = _register_dests(_SHAPE.fanout)
|
|
57
|
+
|
|
58
|
+
inbound("IB_StoreOnce", MLLP(port=_SHAPE.adt_port), router="store_once_router")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@router("store_once_router")
|
|
62
|
+
def route(msg: Message | RawMessage) -> list[str]:
|
|
63
|
+
return ["fanout_identical_body"]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@handler("fanout_identical_body")
|
|
67
|
+
def fanout_identical_body(msg: Message | RawMessage) -> list[Send]:
|
|
68
|
+
# ONE handler → list[Send] of the SAME body to every destination. All N deliveries share this one
|
|
69
|
+
# transform_handoff AND carry the identical body, so the store dedups: one content-addressed
|
|
70
|
+
# shared_body row + N body_ref rows (not N inline copies). Deliberately NO per-destination
|
|
71
|
+
# transform — that would make the bodies distinct and defeat dedup (see harness/config/load for the
|
|
72
|
+
# realistic N-distinct-bodies shape).
|
|
73
|
+
return [Send(dest, msg) for dest in _DESTS]
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
# Copyright (C) 2026 MessageFoundry Organization and contributors
|
|
3
|
+
"""Engine-side sampling — the aggregate view the per-message metrics can't give.
|
|
4
|
+
|
|
5
|
+
Polls the engine's HTTP API on an interval (``/stats``, ``/connections``, ``/status``) to track
|
|
6
|
+
engine-side throughput (Δdone/Δt), backlog, dead-letter accumulation, and DB/WAL growth over the run,
|
|
7
|
+
then measures **drain time** after offered load stops. The :class:`~messagefoundry.console.client`
|
|
8
|
+
``EngineClient`` is synchronous (httpx), so every call runs in a thread via ``run_in_executor`` — the
|
|
9
|
+
load engine's event loop is never blocked. The harness reaches the engine only through this API; it
|
|
10
|
+
never touches the store.
|
|
11
|
+
|
|
12
|
+
**Cluster-wide aggregation.** A ``messagefoundry supervise`` cluster spreads inbounds across several
|
|
13
|
+
shard subprocesses, each with its own API. The poller takes a **list** of engine base-URLs (the
|
|
14
|
+
primary ``--engine`` plus any ``--shard-engine``, de-duped), polls each in turn off the event loop,
|
|
15
|
+
and **sums** each shard's read/written/backlog/in_pipeline/queue_depth/dead into one cluster sample
|
|
16
|
+
(the sum is order-independent, so the sequential per-shard reads need no ordering) — so the no-loss
|
|
17
|
+
reconcile compares cluster-aggregate ``read``/``written``/``backlog`` against the (already cluster-
|
|
18
|
+
aggregate) client ``sent``/``sink_received``, and drain requires **every** shard to empty. With a
|
|
19
|
+
single URL (the default) a sample is byte-identical to the one-shard behavior.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import asyncio
|
|
25
|
+
import time
|
|
26
|
+
from dataclasses import dataclass
|
|
27
|
+
from typing import Sequence
|
|
28
|
+
|
|
29
|
+
from messagefoundry.console.client import ApiError, EngineClient
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class EngineSample:
|
|
34
|
+
"""One engine-side observation. ``read``/``written``/``done``/``dead`` are cumulative since engine
|
|
35
|
+
start, so run totals are last − first. Under a multi-shard cluster every field is the **sum**
|
|
36
|
+
across all polled shards."""
|
|
37
|
+
|
|
38
|
+
elapsed_s: float
|
|
39
|
+
pending: int # outbound stage, status=pending
|
|
40
|
+
inflight: int # outbound stage, status=inflight
|
|
41
|
+
done: int # outbound stage, status=done (delivered)
|
|
42
|
+
dead: int # outbound stage, status=dead (dead-lettered)
|
|
43
|
+
read: int # Σ inbound `read` (messages received)
|
|
44
|
+
written: int # Σ outbound `written` (deliveries made)
|
|
45
|
+
out_dead: int # Σ outbound `errored` (deliveries dead-lettered)
|
|
46
|
+
queue_depth: int # Σ outbound queue_depth (pending + inflight)
|
|
47
|
+
in_pipeline: (
|
|
48
|
+
int # NOT-DONE rows across ALL stages (ingress+routed+outbound) — whole-pipeline gauge
|
|
49
|
+
)
|
|
50
|
+
db_size_bytes: int
|
|
51
|
+
journal_mode: str
|
|
52
|
+
uptime_s: float
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def backlog(self) -> int:
|
|
56
|
+
return self.pending + self.inflight
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(frozen=True)
|
|
60
|
+
class _ShardSample:
|
|
61
|
+
"""A single shard's contribution to one cluster sample (the per-URL summable parts)."""
|
|
62
|
+
|
|
63
|
+
pending: int
|
|
64
|
+
inflight: int
|
|
65
|
+
done: int
|
|
66
|
+
dead: int
|
|
67
|
+
read: int
|
|
68
|
+
written: int
|
|
69
|
+
out_dead: int
|
|
70
|
+
queue_depth: int
|
|
71
|
+
in_pipeline: int
|
|
72
|
+
db_size_bytes: int
|
|
73
|
+
uptime_s: float
|
|
74
|
+
journal_mode: str
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class EnginePoller:
|
|
78
|
+
"""Samples one or more engine APIs off the event loop, aggregates them, and detects post-load
|
|
79
|
+
drain across the whole cluster."""
|
|
80
|
+
|
|
81
|
+
def __init__(
|
|
82
|
+
self, engine_urls: str | Sequence[str], token: str | None, *, origin: float
|
|
83
|
+
) -> None:
|
|
84
|
+
# Accept a single URL (back-compat) or a list. The first URL is the "primary" whose `client`
|
|
85
|
+
# is exposed for one-off preflight reads (served-ports check).
|
|
86
|
+
urls = [engine_urls] if isinstance(engine_urls, str) else list(engine_urls)
|
|
87
|
+
if not urls:
|
|
88
|
+
raise ValueError("EnginePoller needs at least one engine URL")
|
|
89
|
+
# De-dup, order-preserving (primary first): passing the primary --engine ALSO as a
|
|
90
|
+
# --shard-engine would otherwise double-count that shard's read/written/backlog and mask real
|
|
91
|
+
# loss. Distinct shard APIs are unaffected; the single-URL default stays exactly one client.
|
|
92
|
+
seen: set[str] = set()
|
|
93
|
+
deduped: list[str] = []
|
|
94
|
+
for url in urls:
|
|
95
|
+
if url not in seen:
|
|
96
|
+
seen.add(url)
|
|
97
|
+
deduped.append(url)
|
|
98
|
+
self._urls = deduped
|
|
99
|
+
self._token = token
|
|
100
|
+
self._origin = origin
|
|
101
|
+
self._clients: list[EngineClient] = []
|
|
102
|
+
self._samples: list[EngineSample] = []
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def client(self) -> EngineClient | None:
|
|
106
|
+
"""The PRIMARY shard's client (set after :meth:`open`) — for one-off preflight reads."""
|
|
107
|
+
return self._clients[0] if self._clients else None
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def samples(self) -> list[EngineSample]:
|
|
111
|
+
return self._samples
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def baseline(self) -> EngineSample | None:
|
|
115
|
+
return self._samples[0] if self._samples else None
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def final(self) -> EngineSample | None:
|
|
119
|
+
return self._samples[-1] if self._samples else None
|
|
120
|
+
|
|
121
|
+
async def open(self) -> None:
|
|
122
|
+
await asyncio.get_running_loop().run_in_executor(None, self._open_sync)
|
|
123
|
+
|
|
124
|
+
async def close(self) -> None:
|
|
125
|
+
loop = asyncio.get_running_loop()
|
|
126
|
+
clients, self._clients = self._clients, []
|
|
127
|
+
for client in clients:
|
|
128
|
+
await loop.run_in_executor(None, client.close)
|
|
129
|
+
|
|
130
|
+
async def sample_once(self) -> EngineSample | None:
|
|
131
|
+
sample = await asyncio.get_running_loop().run_in_executor(None, self._sample_sync)
|
|
132
|
+
if sample is not None:
|
|
133
|
+
self._samples.append(sample)
|
|
134
|
+
return sample
|
|
135
|
+
|
|
136
|
+
async def run(self, interval: float, stop: asyncio.Event) -> None:
|
|
137
|
+
"""Sample every ``interval`` seconds until ``stop`` is set."""
|
|
138
|
+
await self.sample_once()
|
|
139
|
+
while not stop.is_set():
|
|
140
|
+
try:
|
|
141
|
+
await asyncio.wait_for(stop.wait(), timeout=interval)
|
|
142
|
+
except TimeoutError:
|
|
143
|
+
await self.sample_once()
|
|
144
|
+
|
|
145
|
+
async def await_drain(self, *, timeout: float, interval: float) -> float | None:
|
|
146
|
+
"""Poll until the **whole cluster's** pipeline is empty and inbound/delivery counters stop
|
|
147
|
+
moving. Returns seconds-to-drain, or ``None`` on timeout.
|
|
148
|
+
|
|
149
|
+
Drain requires the *aggregate* ``in_pipeline == 0`` (no NOT-DONE rows in ANY stage of ANY
|
|
150
|
+
shard — ingress, routed, or outbound), the summed outbound backlog + per-edge ``queue_depth``
|
|
151
|
+
at zero, and ``read``/``written`` unchanged across a poll. Because the cluster sample sums
|
|
152
|
+
every shard, this only completes once **every** shard reports ``in_pipeline == 0`` and an
|
|
153
|
+
empty backlog. The ``in_pipeline`` gauge (from ``/stats``) closes the prior blind spot: a
|
|
154
|
+
fully **stalled** router/transform leaves the outbound backlog at 0 but ``in_pipeline > 0``,
|
|
155
|
+
so it no longer reads as drained."""
|
|
156
|
+
loop = asyncio.get_running_loop()
|
|
157
|
+
start = loop.time()
|
|
158
|
+
prev = self.final or await self.sample_once()
|
|
159
|
+
while loop.time() - start < timeout:
|
|
160
|
+
try:
|
|
161
|
+
await asyncio.wait_for(asyncio.sleep(interval), timeout=interval + 1.0)
|
|
162
|
+
except TimeoutError: # pragma: no cover - defensive
|
|
163
|
+
pass
|
|
164
|
+
cur = await self.sample_once()
|
|
165
|
+
if cur is None:
|
|
166
|
+
continue
|
|
167
|
+
stable = prev is not None and cur.read == prev.read and cur.written == prev.written
|
|
168
|
+
if cur.backlog == 0 and cur.queue_depth == 0 and cur.in_pipeline == 0 and stable:
|
|
169
|
+
return loop.time() - start
|
|
170
|
+
prev = cur
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
# --- sync helpers (run in the executor) ----------------------------------
|
|
174
|
+
|
|
175
|
+
def _open_sync(self) -> None:
|
|
176
|
+
clients: list[EngineClient] = []
|
|
177
|
+
for url in self._urls:
|
|
178
|
+
client = EngineClient(url)
|
|
179
|
+
if self._token:
|
|
180
|
+
client.set_token(self._token) # does a /me request to validate
|
|
181
|
+
clients.append(client)
|
|
182
|
+
self._clients = clients
|
|
183
|
+
|
|
184
|
+
def _sample_sync(self) -> EngineSample | None:
|
|
185
|
+
"""Sample every shard and SUM into one cluster observation.
|
|
186
|
+
|
|
187
|
+
Reachability mirrors the single-shard semantics: a shard that is transiently unreachable makes
|
|
188
|
+
the whole sample unavailable (return ``None`` → skip this tick, keep polling), rather than
|
|
189
|
+
silently reporting a too-low aggregate that would poison the baseline/final no-loss math."""
|
|
190
|
+
if not self._clients:
|
|
191
|
+
return None
|
|
192
|
+
shard_samples: list[_ShardSample] = []
|
|
193
|
+
for client in self._clients:
|
|
194
|
+
shard = self._sample_shard(client)
|
|
195
|
+
if shard is None:
|
|
196
|
+
return None # one shard unreachable → skip the aggregate (keep polling)
|
|
197
|
+
shard_samples.append(shard)
|
|
198
|
+
# Journal mode is reported per shard; they share a backend in practice, so take the first
|
|
199
|
+
# (informational only — it doesn't feed the no-loss check).
|
|
200
|
+
return EngineSample(
|
|
201
|
+
elapsed_s=time.perf_counter() - self._origin,
|
|
202
|
+
pending=sum(s.pending for s in shard_samples),
|
|
203
|
+
inflight=sum(s.inflight for s in shard_samples),
|
|
204
|
+
done=sum(s.done for s in shard_samples),
|
|
205
|
+
dead=sum(s.dead for s in shard_samples),
|
|
206
|
+
read=sum(s.read for s in shard_samples),
|
|
207
|
+
written=sum(s.written for s in shard_samples),
|
|
208
|
+
out_dead=sum(s.out_dead for s in shard_samples),
|
|
209
|
+
queue_depth=sum(s.queue_depth for s in shard_samples),
|
|
210
|
+
in_pipeline=sum(s.in_pipeline for s in shard_samples),
|
|
211
|
+
db_size_bytes=sum(s.db_size_bytes for s in shard_samples),
|
|
212
|
+
journal_mode=shard_samples[0].journal_mode,
|
|
213
|
+
uptime_s=max(s.uptime_s for s in shard_samples),
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
@staticmethod
|
|
217
|
+
def _sample_shard(client: EngineClient) -> _ShardSample | None:
|
|
218
|
+
try:
|
|
219
|
+
stats = client.stats()
|
|
220
|
+
conns = client.connections()
|
|
221
|
+
status = client.status()
|
|
222
|
+
except ApiError:
|
|
223
|
+
return None # transient unreachability — caller skips the whole sample
|
|
224
|
+
ob = stats.outbox_by_status
|
|
225
|
+
# `read` is populated only on inbound rows, `written` only on outbound rows — so summing the
|
|
226
|
+
# non-None values partitions inbound vs outbound without guessing role/direction strings.
|
|
227
|
+
read = sum(r.read for r in conns if r.read is not None)
|
|
228
|
+
written = sum(r.written for r in conns if r.written is not None)
|
|
229
|
+
out_dead = sum(r.errored or 0 for r in conns if r.written is not None)
|
|
230
|
+
queue_depth = sum(r.queue_depth or 0 for r in conns if r.queue_depth is not None)
|
|
231
|
+
return _ShardSample(
|
|
232
|
+
pending=ob.get("pending", 0),
|
|
233
|
+
inflight=ob.get("inflight", 0),
|
|
234
|
+
done=ob.get("done", 0),
|
|
235
|
+
dead=ob.get("dead", 0),
|
|
236
|
+
read=read,
|
|
237
|
+
written=written,
|
|
238
|
+
out_dead=out_dead,
|
|
239
|
+
queue_depth=queue_depth,
|
|
240
|
+
in_pipeline=stats.in_pipeline,
|
|
241
|
+
db_size_bytes=status.db.size_bytes,
|
|
242
|
+
uptime_s=status.engine.uptime_seconds,
|
|
243
|
+
journal_mode=status.db.journal_mode,
|
|
244
|
+
)
|
|
@@ -13,6 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
import asyncio
|
|
14
14
|
import contextlib
|
|
15
15
|
import time
|
|
16
|
+
from typing import Sequence
|
|
16
17
|
|
|
17
18
|
from messagefoundry.console.client import ApiError
|
|
18
19
|
|
|
@@ -45,6 +46,8 @@ async def run_load(
|
|
|
45
46
|
sink_port: int = 2700,
|
|
46
47
|
sink_ports: int = 1,
|
|
47
48
|
db_backend: str | None = None,
|
|
49
|
+
skip_preflight: bool = False,
|
|
50
|
+
shard_engines: Sequence[str] = (),
|
|
48
51
|
) -> RunReport:
|
|
49
52
|
ids = ControlIds(prefix=id_prefix)
|
|
50
53
|
# Generate + parse the corpus off the event loop (hl7apy validation is slow) before anything runs.
|
|
@@ -60,7 +63,10 @@ async def run_load(
|
|
|
60
63
|
host=sink_host,
|
|
61
64
|
ports=tuple(sink_port + i for i in range(sink_ports)),
|
|
62
65
|
)
|
|
63
|
-
|
|
66
|
+
# Poll the primary --engine plus every --shard-engine and AGGREGATE (sum) their /stats, so the
|
|
67
|
+
# no-loss reconcile and drain see CLUSTER totals — not just the one shard the --engine names. With
|
|
68
|
+
# no shard_engines this is exactly [engine_url] = byte-identical to the single-shard behavior.
|
|
69
|
+
poller = EnginePoller([engine_url, *shard_engines], token, origin=time.perf_counter())
|
|
64
70
|
pools = [
|
|
65
71
|
(t, ConnectionPool(t, profile.pool_size, correlator, metrics)) for t in profile.targets
|
|
66
72
|
]
|
|
@@ -71,7 +77,14 @@ async def run_load(
|
|
|
71
77
|
try:
|
|
72
78
|
await sink.start()
|
|
73
79
|
await poller.open()
|
|
74
|
-
|
|
80
|
+
if not skip_preflight:
|
|
81
|
+
await _preflight(
|
|
82
|
+
poller, profile
|
|
83
|
+
) # raises PreflightError if unreachable / ports missing
|
|
84
|
+
# When skipped (multi-shard driving): one harness drives MLLP ports spread across several
|
|
85
|
+
# `supervise` shard engines, so no single --engine serves them all. The served-ports check is
|
|
86
|
+
# bypassed; the correlation sink still measures aggregate E2E + no-loss across every shard
|
|
87
|
+
# delivering to this run's --sink-port (set each shard's MEFOR_LOAD_SINK_PORT to match).
|
|
75
88
|
|
|
76
89
|
dispatcher.start()
|
|
77
90
|
poll_task = asyncio.create_task(poller.run(profile.poll_interval_s, poll_stop))
|
|
@@ -61,7 +61,7 @@ from messagefoundry.parsing.message import Message, RawMessage
|
|
|
61
61
|
from messagefoundry.parsing.split import split_by_obr
|
|
62
62
|
from messagefoundry.timezone import convert_hl7_timestamp, to_zone
|
|
63
63
|
|
|
64
|
-
__version__ = "0.2.
|
|
64
|
+
__version__ = "0.2.8"
|
|
65
65
|
|
|
66
66
|
__all__ = [
|
|
67
67
|
"Message",
|