Documentation
¶
Overview ¶
composite.go — the compositeResponder routes a CONFIG-DERIVED set of legs to a native LegResponder and every other leg to a fallback. The conformant CRD leg and DTR forward whenever native mode is on; the conformant PAS pair forwards only when pasNative is set, toggled BOTH-OR-NEITHER so a native submit + sandbox amendment can never split decision authority. The coverage-eligibility leg always routes to the fallback (managed): none of the common Da Vinci RIs implement CoverageEligibilityRequest adjudication; the composite still accepts eligibility but the managed connector makes the decision.
crd_dispatch_native.go — the conformant crd-order-dispatch leg: the payer-side inbound handler + AI-11 subject-bind for an order-dispatch CDS Hooks request (context.dispatchedOrders + performer, resolved from prefetch — NOT draftOrders). The order-dispatch sibling of crd_native.go. The card is advisory (payer Org wins br-payer's First([Organization])); the leg's job is to advertise the questionnaire-package + carry the request to br-payer's order-dispatch-crd.
crd_native.go — the CONFORMANT CRD leg (crd-order-select): the payer-side inbound handler + subject-bind for a conformant CDS Hooks order-select request (context.draftOrders is a FHIR Bundle). This is the only CRD coverage-discovery contract (br-provider's verbatim bytes → br-payer); the minimized crd-order-select leg + its handler are no longer part of the contract.
davincimap.go — translators between SHN's internal leg shapes and the real Da Vinci wire ops. SHN's CRD hook omits the CDS-Hooks-required hookInstance; the DTR leg's ResponseFHIR is the full $questionnaire-package collection Bundle — buildQuestionnairePackage wraps the sandbox Questionnaire, native.go forwards a real partner's package VERBATIM, and extractQuestionnaireFromPackage (consumer-side, called from originate.go) extracts the bare Questionnaire for F5/auto-fill. Deps survive the wire. normalizeCRDCoverage (FR-G25) projects a partner CRD service's coverage-information onto the canonical shnsdk.CardCoverage — this file therefore references shnsdk.CardCoverage (the engine package already depends on shnsdk via nativepas.go).
exchange_ir.go — the Layer-2 Canonical Exchange IR: workstream-NEUTRAL vocabulary the gateway moves and guards but never clinically interprets. Zero Da Vinci, zero provider/payer. A workstream module (Layer 3, e.g. workstream_pa.go) supplies the concrete legTypes and content shapes; this file knows only their neutral envelope. The wire stays sealed workstream-native bytes (AI-2 / OWD-G3): the IR is gateway-INTERNAL, never a neutral wire format.
exchangestore.go — the Layer-2 Exchange correlation seam (AI-1). The in-memory impl is the current default; a durable/expiring/shared impl is a planned future drop-in behind this interface. The store persists a METADATA-ONLY LegRecord — never Content, never bytes — so a durable store cannot silently become a longitudinal clinical store (AI-1).
fhirread.go — self-contained json-level FHIR subject readers for the (C) outbound fence (fenceResponseSubject). These were originally added to the LOCAL sdk/ module but the gateway's standalone Docker build resolves shn-sdk from the published v0.7.0 proxy (no go.work), which does not carry them. Relocating them here makes the gateway closure complete against shn-sdk v0.7.0 (Ruling: no SDK release this slice). They promote to shn-sdk with the LegResponder promotion.
Package gateway is the Smart Gateway: the holder-side integration point that composes identity, per-operation authorization, payload-blind envelopes, FHIR mapping, and per-message profile validation. One binary, two roles (provider and payer), wired by Config.Role. This is the integration heart of UC-01.
inbound.go — recipient-side envelope dispatch and the facility / PHG responders plus shared inbound helpers. Part of package gateway (the Smart Gateway runs every holder role; this file is the inbound-dispatch, facility-disclosure, and patient-authorship surface). Behavior-preserving split of gateway.go (finding C); no logic change. See gateway.go for the package doc.
ingress.go — the DaVinciIngress origination driver: the second origination driver over OriginateLeg. Terminates the three inbound Da Vinci protocols, resolves+inlines prefetch (CRD), drives OriginateLeg per call through the ExchangeStore seam, and wraps each response back into its native envelope. Mounted on the provider role when Config.IngressEnabled.
ingress_crd.go — CRD (CDS Hooks order-select) ingress: parse the conformant inbound request and prove every patient reference resolves to ONE pci before any leg. This is the origination mirror of the inbound H2a fence / bindBundleSubject: on the ingress the payload is EXTERNAL (br-provider), so cross-field patient consistency is not automatic the way it is for the /scenario Originator.
ingress_discovery.go — the static CDS Hooks /cds-services discovery the provider ingress advertises so br-provider's resolvePrefetch knows what to inline. The prefetch templates are the pinned PA set, hand-authored from the two-oracle conformant shape (br-payer's + br-provider's reverse-engineered prefetch needs). DEFERRED: capturing br-payer's LIVE /cds-services as a fixture and a hermetic assertion that pinnedPrefetchKeys ⊇ that captured set — needs br-payer running; until then the superset relationship is asserted by the pinned conformant shape, not by a live-captured fixture.
ingress_dtr.go — DTR ($questionnaire-package) ingress: terminate the inbound SDC fetch and drive the EXISTING dtr-questionnaire-fetch substrate leg (near-relay). The ingress does NOT invoke the Populator and there is no $populate route — br-provider's own DTR app populates locally. It extracts the questionnaire canonical (and, for per-patient authz, the coverage beneficiary) and relays the package Bundle response.
gateway/engine/ingressauth.go
ingressauth.go — the gateway-hosted SMART Backend Services authorization server + bearer verifier for the DaVinciIngress. The gateway is BOTH the authorization server (issues bearers at /oauth/token) and the resource server (verifies them on every ingress route). This is a gateway-EDGE credential — it is NOT substrate authority: authorize() (gateway.go) mints the per-leg token + Hub assertion from the gateway's OWN identity and never reads the inbound Authorization header (AI-11/OWD-6; same boundary as gateway/connectors/smartauth, inbound twin).
Bearers are signed with an EPHEMERAL in-process ES384 key (5-min TTL; a restart makes clients re-fetch). That is sound ONLY while the ingress is single-reachable-instance: cloud public exposure is a planned future enhancement, and the shared-key/JWKS + shared-jti requirement rides that future public-ingress slice.
These routes are PUBLIC once cloud exposure lands — no debug surface, return generic errors — never raw JWT/crypto detail in a response body.
native.go — the native-forward payer LegResponder (Case 1). It forwards each read-only leg to a partner's real Da Vinci endpoint over a SMART-authenticated *http.Client and returns the partner's FHIR. The engine still owns authority (the (A)/(B) inbound fences + the (C) outbound subject fence, now defending a real party), sealing, edge $validate, and audit (AI-11). The PAS legs (nativepas.go) reuse the originator's PUBLISHED shnsdk parsers; the CRD leg normalizes the partner's coverage-information to the canonical shnsdk.CardCoverage (FR-G25, normalizeCRDCoverage in davincimap.go) and re-renders SHN cards with shnsdk.BuildCards, so this file references shnsdk too. It implements the internal, unstable engine.LegResponder (STABILITY: connectors/* is the supported surface); it graduates to connectors/davinci when LegResponder promotes to shnsdk.
nativepas.go — the native PAS legs of the native-forward Responder. They forward pas-claim / pas-claim-update to the partner's /Claim/$submit, normalize the partner's Bundle response into SHN's canonical shape (normalizePASResponse, FR-G28), and drive the gateway-owned shadow ledger + locally-projected PDex EOB (ownership #1). This file owns the shnsdk imports; native.go's read-only legs stay shnsdk-free. The PAS response is parsed with the SAME exported parsers the originator uses (gateway/engine/originate.go) — no new shnsdk symbol.
observer.go — the gateway observer seam: opt-in structured edge events for local inspection tooling (see STABILITY.md).
The observer is ADDITIVE instrumentation at the gateway edge: when Config.Observer is non-nil, the engine emits one structured ObserverEvent at each edge seam — origination legs (roundTrip), the Da Vinci ingress routes, and every $validate call. Events include PAYLOAD SNAPSHOTS: the cleartext FHIR exactly as this gateway saw it at its own edge (where payloads legitimately live — the substrate itself stays payload-blind).
nil Observer (the default) = no emission and no overhead beyond one nil check: the published gateway binary never observes unless its operator asks. Emission MUST NOT change exchange behavior; TestObserver_ConformanceNeutral pins responses byte-identical with the observer on vs off.
order_build.go — gateway-local stub for deferral D-PCB-1 (build-side product-coding gap). shnsdk.BuildServiceRequest is CPT-system-locked, so the gateway cannot build a HCPCS order via the published SDK. This gateway-local GENERIC builder takes the system explicitly — the EXACT shape the SDK will eventually get (BuildServiceRequestCoded). When a real partner consumer needs to build HCPCS orders via the SDK, lift this into sdk/order.go (additive) and honor the D-PCB-1 rejection test before recording it closed. Parity-pinned to shnsdk.BuildServiceRequest for CPT (test/sdkparity/order_coded_parity_test.go) so it cannot drift before the pull-in.
originate.go — the provider-side scenario drivers (UC-01…08): originate a PA exchange, run it through the Hub, and surface the result. Part of package gateway (the Smart Gateway runs every holder role; this file is the provider-origination surface). Behavior-preserving split of gateway.go (finding C); no logic change. See gateway.go for the package doc.
originate_homeoxygen.go — originateDispatch, the provider-data order-dispatch origination prong (handleHomeOxygen = the MBR-OX wrapper; UC-03 provider-data = the MBR-PD-UC03 wrapper).
Unlike the UC-01…08 handlers, originateDispatch originates OFF PROVIDER DATA ONLY: it reads the given member's seeded open order (a DeviceRequest) from the FHIR SoR and drives CRD(order-dispatch) → DTR(operated $populate) → PAS through the substrate. There is no hardcoded order code and no answer book — the order code, the diagnosis, and the supplier ALL come from the SoR (OpenOrder + ResolveByReference of the order's performer). It serves any seeded order-dispatch member: HomeOxygen = MBR-OX (E0431), UC-03 = MBR-PD-UC03 (E1390).
It deliberately does NOT call runCRDThenDTROrder: that helper builds a ServiceRequest from a literal code and originates crd-order-SELECT, whose verdict switch REJECTS any non-PA-required card. The order-dispatch card here is ADVISORY (conditional coverage, NOT auth-needed) — its job is to advertise the HomeOxygen questionnaire — so the gate is NeedsDTR / a questionnaire being present, NOT PARequired(). The genuine verdict is the conditional-coverage A4-pended → A1 (the supplier NPI is verdict-IRRELEVANT; there is no supplier-NPI-verdict branch anywhere here).
originate_resume.go — the provider's mid-flow pend/resume machinery for the attestation scenarios (UC-06 clinician, UC-07 patient): run-to-PENDED, the single-call resume completers, and the two-phase start/complete/cancel handlers. Part of package gateway (the Smart Gateway runs every holder role; this file is the provider-origination resume surface). Behavior-preserving split of gateway.go (finding C); no logic change. See gateway.go for the package doc.
pas_native.go — the CONFORMANT PAS leg (pas-claim): a relaxed full-bundle subject-bind + the payer-side inbound handler for a conformant Da Vinci $submit Claim Bundle (Claim + Patient + Coverage + payor Org + Practitioner + ServiceRequest [+ QuestionnaireResponse], in any order). This is the only PA $submit contract — the minimized pas-claim leg + the strict shnsdk.ParseClaimBundle parse it used are no longer part of the contract. The PAS analog of crd_native.go.
pas_tail.go — the shared LEAN PAS submit→resolve tail, extracted from handleHomeOxygen (the provider-data order-dispatch handler) so the provider-data order-select single-shot lanes (UC-02/03/04, D-PD-1) reuse one path instead of forking a second.
submitClaimAndResolve is the SINGLE-SHOT submit tail: build the conformant Claim Bundle → egress-$validate → originate the pas-claim leg → ingress-$validate → classify the resolved ClaimResponse. There is NO amendment leg on this tail (that is the sandbox UC-04/06 path). A single-shot ServiceRequest sets the Da Vinci PAS infoChanged item extension so the payer gate POLLS the timer-resolved terminal A1 (handlePASClaimNative); a single-shot DeviceRequest (HomeOxygen) does NOT — its order type alone routes it to the same poll. infoChanged is the payer-side poll DISCRIMINATOR, NOT a verdict input (the verdict is br-payer's code-keyed CQL constant; the A4→A1 is br-payer's own timer).
patientaccess.go — the CMS-0057 Patient Access REST edge (FR-28). Part of package gateway (the Smart Gateway runs every holder role; this file is the payer's patient-access surface). Behavior-preserving split of gateway.go (finding C); no logic change. See gateway.go for the package doc.
payer.go — the payer-side DTR questionnaire responder and the shared (C) outbound subject fence. Part of package gateway (the Smart Gateway runs every holder role; this file is the payer-adjudication surface). The conformant PAS inbound handlers live in pas_native.go; the minimized CRD/PAS handlers are no longer part of the contract. See gateway.go for the package doc.
gateway/engine/relayresp.go
uc04_attest.go — the provider-data UC-04 DTR ATTESTATION answer-map builder.
br-payer's UC-04 questionnaire (HomeHealthAssessment) is an ADAPTIVE questionnaire with 0 CQL expression items, so the operated $populate auto-pops nothing — the spine's DTR step produces an empty QR. UC-04's DTR is ATTESTATION: the answers are filled from the provider's seeded clinical data (manual entry), NOT auto-populated. uc04AttestationAnswers builds that answer map FROM the seeded order so every answer TRACES TO SEED:
- linkId 1.1 (service category, a coded answer): SNOMED 91251008 (Physical therapy) — derived from the order's clinical nature. The seeded order carries HCPCS G0151 ("services of a qualified physical therapist in the home-health setting"), so the home-health service category is, faithfully, physical therapy. This is faithful attestation of the ORDER's service type, NOT payer-matching.
- linkId 3.1 (primary diagnosis, a text answer): the dx display read from the order's reasonCode (coding.display, falling back to the CodeableConcept text). Read FROM the order — never hardcoded.
HONESTY FENCE: every attested answer traces to the seeded order; we never hardcode a value to match the payer; the QR is VERDICT-INERT — br-payer's verdict is a code-keyed CQL constant on G0151 and the A4→A1 is its pend-resolution timer, so these answers do NOT drive the verdict. No "clinical value → PA" or "supplier-NPI verdict" claim is made.
workstream_pa.go — the Layer-3 Prior-Authorization workstream module. It NAMES AND RELOCATES what was inlined in the fused engine: the per-leg-type authority frames, operations, transaction types, scopes, and leg-physics. The Layer-2 primitives (OriginateLeg, handleInbound's FulfillLeg dispatch) read this catalog instead of carrying the literals inline, so the origination and inbound sides can no longer drift. A future workstream (X12/EDI, payer-to-payer) is a sibling module with its own catalog; Layers 1-2 do not change.
Index ¶
- Constants
- Variables
- func BuildServiceRequestCoded(system, code, display, dxCode, patientRef string) ([]byte, error)
- func DiscoverCRDServiceID(ctx context.Context, client *http.Client, base, override string) (string, error)
- func EnableIngressForTest(cfg *Config)
- func NewInMemoryExchangeStore() *inMemoryExchangeStore
- func NewNativePopulator(client *http.Client, url string) *nativePopulator
- func NewSandboxAdjudicator(sor SystemOfRecord, clock func() time.Time) shnsdk.Adjudicator
- func ParseCoverageEligibilityResponsePatient(data []byte) (string, error)
- func ParsePASResponsePatients(b []byte) ([]string, error)
- type Config
- type ConfigPayerRouter
- type Content
- type Demo
- type Exchange
- type ExchangeStore
- type FeedPayerRouter
- type FilledItem
- type Gateway
- type IngressClientRegistration
- type Leg
- type LegPhysics
- type LegRecord
- type LegResponder
- type LegResult
- type NativeOption
- type ObserverEvent
- type PayerDirectoryEntry
- type PayerRouter
- type PersonaRef
- type PopulateContext
- type Populator
- type RelayError
- type Store
- type StubHolderData
- func (d *StubHolderData) AuthNumber(serviceRequestRef string) (string, bool)
- func (d *StubHolderData) BeginClaimUpdate(subjectPCI, correlationID string) (bool, error)
- func (d *StubHolderData) ClinicalContext(memberID string) (shnsdk.ClinicalContext, bool)
- func (d *StubHolderData) CoverageInforce(memberID string) (inforce bool, reason string)
- func (d *StubHolderData) EOBByID(eobID string) ([]byte, bool)
- func (d *StubHolderData) EOBsForPatient(subjectPCI string) ([][]byte, bool)
- func (d *StubHolderData) FacilityRecords(memberID string) (map[string][]byte, bool)
- func (d *StubHolderData) FinalizeClaimUpdate(subjectPCI, correlationID string) error
- func (d *StubHolderData) OpenCoverage(memberID string) ([]byte, bool)
- func (d *StubHolderData) OpenOrder(_ string) ([]byte, bool)
- func (d *StubHolderData) PatientFHIRRef(memberID string) (string, bool)
- func (d *StubHolderData) RecordEOB(subjectPCI, eobID string, eobJSON []byte) error
- func (d *StubHolderData) RecordPendedClaim(subjectPCI, correlationID string) error
- func (d *StubHolderData) ReleaseClaimUpdate(subjectPCI, correlationID string) error
- func (d *StubHolderData) Reset()
- func (d *StubHolderData) ResolveByReference(_ string) ([]byte, bool)
- func (d *StubHolderData) ResolvePatient(memberID string) (pci string, demo Demo, found bool)
- func (d *StubHolderData) StoreAuthNumber(serviceRequestRef, preAuthRef string) error
- func (d *StubHolderData) SupplementalReport(memberID string) ([]byte, bool)
- type SystemOfRecord
Constants ¶
const ( KindRequestResponse = "request-response" KindNotification = "notification" EffectReadOnly = "readonly" EffectMutating = "mutating" TimingSync = "sync" TimingAsync = "async" LocalitySubstrate = "substrate-leg" LocalityHolderLocal = "holder-local" )
const ( LegOutcomeRouted = "routed" LegOutcomeAnswered = "answered" LegOutcomeDenied = "denied" LegOutcomeUnreachable = "unreachable" LegOutcomeFailed = "failed" )
LegOutcome values passed to Config.LegMetric: "routed" when an origination leg is attempted, then exactly one terminal outcome.
Variables ¶
var CanaryTwins = map[string]string{
"MBR-COVERED": "MBR-CANARY-COVERED",
"MBR-NOTCOVERED": "MBR-CANARY-NOTCOVERED",
"MBR-UC04": "MBR-CANARY-UC04",
"MBR-UC05": "MBR-CANARY-UC05",
"MBR-UC05-NOCONSENT": "MBR-CANARY-UC05-NOCONSENT",
"MBR-UC06": "MBR-CANARY-UC06",
"MBR-UC07": "MBR-CANARY-UC07",
"MBR-UC07HCPCS": "MBR-CANARY-UC07HCPCS",
"MBR-UC08": "MBR-CANARY-UC08",
}
CanaryTwins maps each sandbox scenario member to its dedicated canary twin (observability Phase 3, settled decision #1): the monitor's scenario canary drives ONLY these members, so continuous canary runs never mutate the shared demo personas' state (EOB accumulation, auth-number overwrites) and canary audit records are attributable by PCI. Twins share the original's birthDate and take family "<orig>-Canary" — the member id alone makes the PCI distinct. internal/fhirseed mirrors this table (census-pinned by its canary_test.go).
var PersonaRefs = []PersonaRef{
{"coveredPci", "MBR-COVERED"},
{"notCoveredPci", "MBR-NOTCOVERED"},
{"uc04Pci", "MBR-UC04"},
{"uc05Pci", "MBR-UC05"},
{"uc06Pci", "MBR-UC06"},
{"uc07Pci", "MBR-UC07"},
{"uc08Pci", "MBR-UC08"},
{"uc07HcpcsPci", "MBR-UC07HCPCS"},
}
PersonaRefs is the canonical ordered persona enumeration. Treat it as read-only — it is shared by multiple consumers (devstack, holdersim) and must not be mutated.
Functions ¶
func BuildServiceRequestCoded ¶ added in v0.10.0
BuildServiceRequestCoded builds a DRAFT US-Core ServiceRequest with an explicit procedure code system (CPT or HCPCS). Generic form of shnsdk.BuildServiceRequest (deferral D-PCB-1).
func DiscoverCRDServiceID ¶ added in v0.3.0
func DiscoverCRDServiceID(ctx context.Context, client *http.Client, base, override string) (string, error)
DiscoverCRDServiceID resolves the partner's CDS Hooks order-select service id from GET {base}/cds-services (FR-G26, OWD-G8). If override is non-empty it is returned immediately (escape hatch for partners whose hook name differs from SHN's origination hook — e.g. br-payer's order-sign service). Otherwise the listing is fetched, filtered to services whose hook matches SHN's crdHook ("order-select"), and the id of exactly one match is returned. Zero matches → error (fail-closed); multiple matches → error (ambiguous; set PAYER_DAVINCI_CRD_SERVICE_ID). A non-2xx or parse error is a fatal boot error (fail-closed per FR-G26).
func EnableIngressForTest ¶ added in v0.4.0
func EnableIngressForTest(cfg *Config)
EnableIngressForTest enables the Da Vinci ingress routes AND the test-only auth bypass on cfg. It is the ONLY affordance that sets ingressAuthBypass; build()/main MUST never call it (enforced by ingress_imagepurity_test.go — the scaffold image-purity pattern).
func NewInMemoryExchangeStore ¶ added in v0.4.0
func NewInMemoryExchangeStore() *inMemoryExchangeStore
NewInMemoryExchangeStore is the default ExchangeStore. Reset-cleared, no TTL — a durable/expiring/shared backend is a planned future drop-in behind ExchangeStore.
func NewNativePopulator ¶ added in v0.2.0
NewNativePopulator builds the pass-through backend. client is the substrate HTTP client.
func NewSandboxAdjudicator ¶
func NewSandboxAdjudicator(sor SystemOfRecord, clock func() time.Time) shnsdk.Adjudicator
NewSandboxAdjudicator builds the default Adjudicator over a SystemOfRecord. clock is used only by PriorAuth (validUntil); a nil clock defaults to time.Now.
func ParseCoverageEligibilityResponsePatient ¶ added in v0.2.0
ParseCoverageEligibilityResponsePatient extracts patient.reference from a CoverageEligibilityResponse JSON (e.g. "Patient/MBR-COVERED"). It errors if the resourceType is not CoverageEligibilityResponse or the patient reference is absent. Used by the (C) outbound fence (coverage-eligibility leg): the engine compares the returned ref to the inbound member-namespace ref so a connector cannot swap the patient between the request it was handed and the response it returned. Exported because test/adversarial uses it directly.
func ParsePASResponsePatients ¶ added in v0.2.0
ParsePASResponsePatients returns every patient reference in a PAS response: a bare ClaimResponse (approved/denied) carries one; a Bundle (pended) carries a ClaimResponse (+ possibly other resources) — collect every ClaimResponse's .patient.reference. Errors if none found. json-level, no FHIR lib. Used by the (C) outbound fence (pas-claim/pas-claim-update legs) and by test/adversarial. Exported because test/adversarial uses it directly.
Types ¶
type Config ¶
type Config struct {
Role string // "provider" | "payer" | "facility"
HolderID string
// PayerRouter resolves a Coverage.payor identity → payer holder id (FR-G40). REQUIRED on the
// provider side: there is NO default payer. Every payer leg's recipient is derived from the
// patient's own Coverage via recipientFor (AI-G11 / OWD-G10) — a miss (no coverage / no
// parseable payer / no directory mapping) fails closed with a legible 422, never a default
// route. Replaced the deleted CounterpartID. The payer side does not use it — it replies to
// the inbound envelope's Sender.
PayerRouter PayerRouter
// OriginationProfile selects the per-UC behavior lane: "" / "sandbox" = the sandbox
// shape (default, SHN-produced, byte-unchanged); "provider-data" = originate every UC off
// the provider's seeded SoR and drive real br-payer verdicts (Mode A). targetsBrPayer keys
// the contained-insurer / absolute-refs / R-8 ingress-skip handling on it. Spec 2B-bis/2C.
OriginationProfile string
// Identity is the gateway's substrate identity: its holder signing key (used to
// sign holder assertions and patient-access audit records) plus its envelope-
// encryption keypair (used to open inbound sealed payloads and seal responses).
Identity shnsdk.Identity
AuthzURL string
AuthzPub ed25519.PublicKey
// HubTransportPub verifies the per-hop X-Hub-Assertion the Hub sends with
// every /substrate/inbound forward (per-hop transport auth). REQUIRED
// for roles that mount /substrate/inbound (payer/facility/phg): New panics
// without it — mandatory enforcement, no "configured off" state.
HubTransportPub ed25519.PublicKey
HubURL string // provider only
Reg shnsdk.Registry
Validator shnsdk.Validator
// SoR reads the holder's backing system of record (resolve/coverage/clinical/
// supplemental/facility-records). E2 swaps in a FHIR client; demo uses the stub.
SoR SystemOfRecord
// Store is the gateway's own business state (auth numbers, pended-claim ledger,
// issued EOBs). Demo: in-memory stub; separated: holdersim; later: gateway Postgres.
Store Store
// Adjudicator is the payer's decision surface (eligibility/order-select/
// questionnaire/prior-auth). REQUIRED for the payer role; New panics without
// it. The default is NewSandboxAdjudicator (the same sandbox decisions the
// gateway made inline before); a partner injects their own. The same interface backs the public SDK
// Responder, so one Adjudicator works against both surfaces (Edge premise).
Adjudicator shnsdk.Adjudicator
// Responder is the payer content seam. Normally left nil and DERIVED from
// Adjudicator in NewGateway (keeping the STABILITY-supported Adjudicator
// injection seam working). A test/partner MAY inject a custom LegResponder.
Responder LegResponder
// PayerDavinciNative reports that the payer Responder native-forwards the read-only
// legs to a REAL partner Da Vinci endpoint (PAYER_DAVINCI_BASE_URL set). When true the
// DTR $questionnaire-package response is a FOREIGN Da Vinci Bundle (dtr-std-questionnaire /
// dtr-questionnaireresponse profiles) that SHN — which hosts US Core only — cannot
// $validate; like the conformant crd-order-select / pas-claim legs (R-8),
// the DTR response is a NEAR-RELAY: the trust-critical subject fence still runs, but the
// engine does NOT foreign-$validate it. false ⇒ the sandbox path (SHN's own
// US-Core-resolvable package), which still egress-$validates byte-identically. FR-G28.
PayerDavinciNative bool
// Populator is the DTR population seam (provider-local). Normally left nil and
// DEFAULTED to the managed backend (today's FillQuestionnaire) in New; the native
// pass-through backend is injected by config (PROVIDER_DTR_NATIVE). A test MAY
// inject a custom Populator.
Populator Populator
// IngressEnabled mounts the Da Vinci ingress routes on the provider role.
// Set from PROVIDER_DAVINCI_INGRESS by app.go. The routes fail-closed without
// ingressAuthBypass (real inbound UDAP auth is a planned future enhancement), so
// enabling them in prod is safe — they reject every call.
IngressEnabled bool
// IngressBaseURL is the gateway's CONFIG-PINNED public base URL: the SMART
// Backend Services aud (assertion + bearer) and the advertised token endpoint.
// Never request-derived (no Host-header spoof). Required when IngressEnabled and
// not bypassed. Set from PROVIDER_DAVINCI_INGRESS_BASE_URL by app.go.
IngressBaseURL string
// IngressClients are the config-registered inbound clients (client_id →
// public key + scopes). Required (>=1) when IngressEnabled and not bypassed.
IngressClients map[string]IngressClientRegistration
Client *http.Client
Clock func() time.Time
NPI string
// CorrelationGen generates a new correlation ID for each outbound scenario
// request. Defaults to newCorrelationID (crypto-random 128-bit hex string).
// Override in tests for deterministic IDs.
CorrelationGen func() string
// ConsentURL is the Trust-operated Global Person Consent service URL (facility
// only). The facility's consent backstop re-confirms a TREAT permit here
// before releasing any records. When empty the backstop fails closed (no consent
// service ⇒ no disclosure).
ConsentURL string
// AuditURL is the Audit Plane's base URL. Used by the payer to append a
// patient-access-read record (FR-29/FR-33) when it serves a Patient Access API
// read. The Patient Access read path is FAIL-CLOSED: a gateway with no AuditURL
// has no audit capability, so serveEOB disables the read (502) rather than
// serving it unaudited, and a failed audit append also blocks the read (502).
AuditURL string
// PHGURL is the Trust-operated PHG base URL. Used by the provider scenario for
// UC-08 demo orchestration: after the PAS denial, the provider queries the PHG
// denial view (GET /denial?pci=<pci>) to surface the patient-rendered reason.
// This stands in for the patient app in the Connectathon demo (provider→PHG
// call is orchestration only, not a substrate leg). Empty → skip the PHG query.
PHGURL string
// Observer, when non-nil, receives a structured ObserverEvent at each
// gateway-edge seam (origination legs, Da Vinci ingress, $validate calls).
// PAYLOADS INCLUDED — cleartext FHIR as seen at this edge. nil (the
// default) = no observation. MAY BE CALLED CONCURRENTLY (handlers run on
// concurrent goroutines); implementations must be goroutine-safe —
// observer.Hub.Emit locks internally. Additive instrumentation only:
// emission must not change exchange behavior
// (TestObserver_ConformanceNeutral). See STABILITY.md; the SHN Kit's
// supervisor always sets it, prod deployments never have it on unless the
// operator opts in via OBSERVER_ADDR.
Observer func(ObserverEvent)
// LegMetric, when non-nil, receives one outcome string per origination-leg
// event at the roundTrip choke point: LegOutcomeRouted when a leg is
// attempted, then exactly one terminal outcome — Answered (the counterpart
// responded: 2xx or relayed app non-2xx), Denied (the Authorization
// Framework denied the leg — a policy decision, not an error), Unreachable
// (the Hub could not be reached / did not route), or Failed (anything
// else). nil (the default, and the published-gateway posture) = no
// emission. MAY BE CALLED CONCURRENTLY; implementations must be
// goroutine-safe and must never block — the callback sits on the request
// path. Additive instrumentation only: emission must not change exchange
// behavior (TestLegMetric_ConformanceNeutral). Carries NO payloads.
LegMetric func(outcome string)
// contains filtered or unexported fields
}
Config wires a gateway. The same struct constructs all roles; provider-only fields (HubURL) are unused on the payer/facility side.
type ConfigPayerRouter ¶ added in v0.18.0
type ConfigPayerRouter struct {
// contains filtered or unexported fields
}
ConfigPayerRouter is the static resolver: a provider-maintained map. (FeedPayerRouter, network discovery, is the feed-derived resolver behind this same interface.)
func NewConfigPayerRouter ¶ added in v0.18.0
func NewConfigPayerRouter(entries []PayerDirectoryEntry) (*ConfigPayerRouter, error)
NewConfigPayerRouter builds a router; a duplicate (system,value) is a hard error (ambiguous routing).
func (*ConfigPayerRouter) Resolve ¶ added in v0.18.0
func (r *ConfigPayerRouter) Resolve(p shnsdk.PayerIdentifier) (string, bool)
type Content ¶ added in v0.4.0
Content is a typed-opaque handle on a workstream payload. The IR validates it at the edge (FR-36/FR-G29) and binds its subject for authority, but never reads its clinical semantics. WorkstreamType identifies the owning module (read live by OriginateLeg's selection-seam guard). ProfileID is a RESERVED routing hint — validation is meta.profile-driven (every call site leaves ProfileID unset), so ProfileID is never the validation key; it is kept as the committed Content shape for future per-call profile pinning (PH-G3) and has no current reader (a reserved seam, not dead code). Bytes is the FHIR/payload bytes that reach the wire.
type Demo ¶
type Demo struct {
BirthDate, FamilyName string
}
Demo holds the demographics a holder knows about a member, used to derive the substrate PCI (AI-5: PCI is computed from member + demographics, never the bare member ID).
type Exchange ¶ added in v0.4.0
Exchange is one correlated business interaction: a PA case today; a member-transfer / query / remittance later. It holds the correlation root and its legs.
DECISION PIN (migration-class): Exchange.ID is the PARENT correlation root that GROUPS legs; each Leg keeps its OWN per-leg substrate CorrelationID (minted by Config.CorrelationGen) as the child. The parent↔child relationship is fixed HERE, before any durable store or audit record references it — changing it later is a migration, not an edit. The durable, expiring store that replaces the in-memory exchange map is a planned future drop-in. No per-leg binding fence (gateway.go VerifyBound, inbound.go subject fence) is weakened by this grouping — Exchange.ID never enters a sealed envelope.
type ExchangeStore ¶ added in v0.4.0
type ExchangeStore interface {
Begin(workstream string) *Exchange
AppendLeg(exchangeID string, rec LegRecord) error
Get(exchangeID string) (*Exchange, bool)
}
ExchangeStore groups the legs of one correlated business interaction. Begin mints the parent Exchange.ID; AppendLeg records a completed leg's metadata projection; Get reads back.
Aliasing contract: Begin/Get return the store's live *Exchange. A caller MUST NOT read the returned pointer's mutable state (notably .Legs) concurrently with a store mutation on the same exchange — it is safe only because the current in-memory impl runs one synchronous ingress call per exchange (callers use Begin's result for its .ID, never to read .Legs). A durable/shared impl that admits concurrent readers must return a snapshot copy instead.
type FeedPayerRouter ¶ added in v0.18.0
type FeedPayerRouter struct {
// contains filtered or unexported fields
}
FeedPayerRouter is the feed-derived resolver: it indexes the live converged /holders registry (operator-attested payer-id claims, FR-G41) to map a Coverage.payor identity → payer holder id. It resolves fresh on every call, so a post-boot feed registration/rotation is visible without a restart (the FR-G10 no-restart property). Ambiguity — a (system,value) claimed by more than one holder — FAILS CLOSED (ok=false), the same defense the DB UNIQUE(system,value) enforces (AI-G12). It considers ONLY role=payer entries: payer-ids on a non-payer entry (a manifest-seeded holder that bypasses the registrar role-gate) are never routed to — the router self-fails-closed on role rather than trusting the upstream 400-gate (authority gates on holder_role==payer).
func NewFeedPayerRouter ¶ added in v0.18.0
func NewFeedPayerRouter(reg shnsdk.Registry) *FeedPayerRouter
NewFeedPayerRouter builds a router backed by reg (a value type whose internals are shared; the router sees live poller updates).
func (*FeedPayerRouter) Resolve ¶ added in v0.18.0
func (r *FeedPayerRouter) Resolve(p shnsdk.PayerIdentifier) (string, bool)
type FilledItem ¶ added in v0.2.0
type FilledItem struct {
LinkID string `json:"linkId"`
Answer string `json:"answer"`
Origin string `json:"origin"`
SourceRef string `json:"sourceRef,omitempty"`
}
FilledItem is the gateway-engine-LOCAL attribution surface for a DTR auto-filled QR item (console response, QRItems field). The SDK's FillQuestionnaire drops the FilledItem summary (UI-only); the gateway reconstructs it via fillSummary from the ClinicalContext. JSON tags are byte-for-byte compatible with the original dtr.FilledItem shape so the console response format is unchanged.
type Gateway ¶
type Gateway struct {
// contains filtered or unexported fields
}
Gateway is a constructed holder gateway.
func New ¶
New constructs a Gateway. The clock defaults to time.Now and the client to http.DefaultClient when unset.
func (*Gateway) ExchangeSnapshot ¶ added in v0.4.0
ExchangeSnapshot returns a copy of the gateway's current Exchanges (test observability of the metadata-only correlation seam). It is a DEV/TEST-ONLY accessor, NOT a stable cross-impl API: it returns nil for any store that is not the in-memory impl (a durable store would need its own observability), so Gate-1 tests rely on it only against the in-memory default.
func (*Gateway) OriginateLeg ¶ added in v0.4.0
func (g *Gateway) OriginateLeg(ctx context.Context, r *http.Request, recipient, legType, pci, correlationID, custodian string, content Content) ([]byte, error)
OriginateLeg is the origination leg-primitive: it runs one authorized, sealed, Hub-routed exchange for legType, reading the authority frames / operations / scope from `paCatalog` (the PA Layer-3 module) instead of taking them as positional literals. recipient stays a parameter (payer legs derive it from the patient's Coverage via recipientFor — no default; facility/phg legs target a LookupByRole result). An unknown legType is a caller bug (the Originator only passes catalog legTypes) and fails closed with an error.
The content.WorkstreamType guard is the SELECTION SEAM in embryo: today exactly one module exists, so it fail-closes anything not tagged workstreamPA; when a second workstream lands this becomes `catalogFor(content.WorkstreamType)`. So the catalog is single-source-of-truth across both edges NOW (origination + the handleInbound FulfillLeg dispatch read the same `paCatalog`, hence "cannot drift"), and module-neutral LATER — this seam is reserved but not yet code-enforced (the primitive still names `paCatalog`). This is the origination MIRROR of the payer-side FulfillLeg pattern.
type IngressClientRegistration ¶ added in v0.4.0
type IngressClientRegistration struct {
Alg string // "ES384" | "RS384"
PublicKeyPEM []byte // PEM SubjectPublicKeyInfo
Scopes []string // permitted scopes
}
IngressClientRegistration is a config-registered inbound client (a provider EHR) the ingress trusts: its public key + permitted scopes. Registration is config-based; UDAP dynamic client registration is a planned future enhancement.
type Leg ¶ added in v0.4.0
type Leg struct {
Type string
Physics LegPhysics
Content Content
Subjects []string
}
Leg is one step of an Exchange: a sealed substrate round-trip or a holder-local operation. It carries the workstream-defined legType, the Content moved on it, and its leg-physics classification. Subjects are the PCI(s) authority binds to. This is SET-SHAPED from day one (PA puts exactly one element) so the IR does not bake in a singular assumption it would have to migrate out of; the bulk MANY-subjects authority basis (a roster / Group-attribution primitive) is a different, deferred Layer-1 primitive, NOT N× the single-PCI binding modeled here.
func (Leg) Project ¶ added in v0.4.0
Project is the SINGLE chokepoint where clinical bytes are dropped: the in-flight Leg (carrying Content) projects to the metadata-only LegRecord the store keeps. There is no other path from Leg to the store, so "bytes never reach the durable seam" is enforced at one reviewable line — l.Content is intentionally NOT carried.
type LegPhysics ¶ added in v0.4.0
type LegPhysics struct {
Kind string // KindRequestResponse | KindNotification
Effect string // EffectReadOnly | EffectMutating
Timing string // TimingSync | TimingAsync
Locality string // LocalitySubstrate | LocalityHolderLocal
}
LegPhysics classifies a leg on four workstream-independent axes. These four drive transport / authority / audit / commit / lifecycle uniformly, regardless of workstream. notification + async are headroom (no PA scenario exercises them) that keeps async-pend / payer-to-payer / Provider Access additive.
type LegRecord ¶ added in v0.4.0
type LegRecord struct {
Type string
CorrelationID string
Subjects []string
Physics LegPhysics
Outcome string // a non-clinical metadata label (e.g. approved | pa-required | pended | denied | ok | error | complete) — gates nothing; NEVER clinical content
}
LegRecord is the metadata-only projection of a completed leg that the store persists. It carries NO Content and NO bytes — by construction, never by discipline.
type LegResponder ¶ added in v0.2.0
type LegResponder interface {
Handle(ctx context.Context, leg, corrID, subjectPCI string, requestFHIR []byte) (LegResult, error)
}
LegResponder is the per-leg payer CONTENT seam (FHIR-in / FHIR-out). The engine owns authority (the A/B inbound fences + the C outbound fence), sealing, edge $validate, and audit; the connector owns content only — the decision and the response FHIR.
leg is the inbound TransactionType. corrID + subjectPCI are engine-owned, leg-invariant authority outputs the connector needs for builders/Store keys (subjectPCI is the token's PCI; the connector never resolves it). requestFHIR is the already-opened, already-authority-fenced request plaintext.
func NewCompositeResponder ¶ added in v0.2.0
func NewCompositeResponder(native, fallback LegResponder, pasNative bool) LegResponder
NewCompositeResponder routes the Da Vinci legs (crd-order-select, dtr-questionnaire-fetch) to native and — when pasNative — the conformant PAS pair; everything else (including coverage-eligibility) routes to fallback. coverage-eligibility is always managed: no common Da Vinci RI implements CoverageEligibilityRequest adjudication.
func NewNativeResponder ¶ added in v0.2.0
func NewNativeResponder(client *http.Client, baseURL, crdServiceID string, store Store, clock func() time.Time, opts ...NativeOption) LegResponder
NewNativeResponder builds the native-forward Responder over a ready *http.Client (in production a smartauth bearer client; in tests a fixed-bearer client). crdServiceID is the partner's CDS Hooks order-select service id, resolved at boot via DiscoverCRDServiceID (FR-G26). store is the gateway-owned Store the PAS legs use (pended ledger + EOB); a nil store is valid for a read-only-only native responder. clock is used for the gateway-projected EOB `created`; nil ⇒ time.Now.
func NewSandboxResponder ¶ added in v0.2.0
func NewSandboxResponder(adj shnsdk.Adjudicator, sor SystemOfRecord, store Store, clock func() time.Time) LegResponder
type LegResult ¶ added in v0.2.0
type LegResult struct {
ResponseFHIR []byte // sealed back; engine (C)-fences + egress-$validates (FHIR legs)
SideEffectFHIR [][]byte // payer-local FHIR to persist (EOB); engine egress-$validates each before Commit
Status int // connector-signalled HTTP outcome (409/422); 0 = proceed
Message string // body for a non-zero Status
Commit func() error // NON-FHIR durable state (Store writes); fired after buildResponseLeg, before writeLeg; error => 502
Rollback func() // undo a claim acquired in Handle; engine arms defer-rollback-unless-committed
// ResponseRelayed reports that ResponseFHIR is a verbatim relay of a foreign holder's bytes
// (SHN did not produce it). When true the engine SKIPS the response egress-$validate (R-8:
// foreign Da Vinci profiles are unresolvable in SHN's US-Core-only validator). SHN-produced
// side-effects (the EOB) are $validated unconditionally. Zero value = strict. Only the
// native-forward responder sets this.
ResponseRelayed bool
// ResponseSubjectForeign reports that ResponseFHIR's patient subject is in a foreign
// (non-SHN-member) namespace (a real br-payer answers Patient/SubscriberExample), so a
// member-match against the bound request patient is a category error. When true the engine
// SKIPS the (C) ClaimResponse member-fence (R-7). The SHN-produced EOB side-effect is
// member-fenced unconditionally. Zero value = strict. Only the native-forward responder sets
// this. (Two flags, not one: the conformant-mock north star is SHN-produced-yet-foreign-
// namespace — $validate must stay ON while the member-fence stands down; a fused bool would
// skip $validate on an SHN-produced resource, an FR-36 violation.)
ResponseSubjectForeign bool
}
LegResult is what a LegResponder returns.
func NormalizePASResponseForTest ¶ added in v0.3.0
NormalizePASResponseForTest is a thin exported wrapper around normalizePASResponse for the test/adversarial package, which cannot access unexported engine symbols. Production code must always call normalizePASResponse directly (nativepas.go). Named *ForTest to signal it is a test seam, not a public API.
type NativeOption ¶ added in v0.6.0
type NativeOption func(*nativeResponder)
NativeOption configures optional nativeResponder behavior.
func WithCDSBaseURL ¶ added in v0.6.0
func WithCDSBaseURL(cdsBaseURL string) NativeOption
WithCDSBaseURL overrides the base used for CDS Hooks (CRD) posts, for partners whose CDS Hooks endpoint is NOT co-located with their FHIR base — e.g. br-payer serves CDS Hooks at root /cds-services but FHIR ops under /fhir. Unset ⇒ CDS posts use the FHIR baseURL (co-located default, the prior behavior). FR-G28 / OWD-G8.
func WithCRDCoverageBundle ¶ added in v0.27.0
func WithCRDCoverageBundle(on bool) NativeOption
WithCRDCoverageBundle enables wrapping the CRD request's bare prefetch.coverage into a searchset Bundle before forwarding — such a partner's order-sign `coverage` prefetch is a SEARCH template (Coverage?beneficiary=…) demanding a searchset Bundle, while the SHN spine carries a bare Coverage (provider routing + payer-side bind both read bare, crd_native.go). Idempotent: an already-Bundle coverage is left as-is. Unset ⇒ forward the coverage verbatim (br-payer's shape). Set via PAYER_DAVINCI_CRD_COVERAGE_BUNDLE (per-partner, opt-in).
func WithCRDDispatchService ¶ added in v0.12.0
func WithCRDDispatchService(serviceID, hook string) NativeOption
WithCRDDispatchService configures the partner's order-dispatch CDS service id + hook for the crd-order-dispatch leg (distinct from order-select's crdServiceID/crdHookOverride). ONE payer-gw serves both: crd-order-select→order-sign-crd, crd-order-dispatch→order-dispatch-crd.
func WithCRDHook ¶ added in v0.11.0
func WithCRDHook(hook string) NativeOption
WithCRDHook sets the CDS Hooks hook value the native-forward stamps on the CRD request before forwarding, to match the partner's configured CRD service (e.g. br-payer's order-sign-crd demands hook:order-sign while SHN originates the canonical order-select). Unset ⇒ forward the originator's hook verbatim (the prior behavior).
func WithPendReQuery ¶ added in v0.11.0
func WithPendReQuery(timeout, interval time.Duration) NativeOption
WithPendReQuery overrides the PAS pend re-query poll timeout + interval (E2). Zero values keep the defaults. Used to make the hermetic nativeResponder tests fast (short interval) and to let the harness tune the bound relative to the payer's resolution delay (E4).
type ObserverEvent ¶ added in v0.19.0
type ObserverEvent struct {
Time time.Time `json:"time"`
Kind string `json:"kind"`
LegType string `json:"legType,omitempty"`
Direction string `json:"direction,omitempty"` // "originate" | "ingress" | "validate" | "sor"
CorrelationID string `json:"correlationId,omitempty"`
Counterpart string `json:"counterpart,omitempty"`
AuthorityFrame string `json:"authorityFrame,omitempty"`
Op string `json:"op,omitempty"`
Status int `json:"status,omitempty"` // relayed recipient app-status (non-2xx relay)
Payload json.RawMessage `json:"payload,omitempty"`
Detail string `json:"detail,omitempty"`
}
ObserverEvent is one structured observation at the gateway edge. Kinds:
leg.originated an origination leg is about to be sent (Payload = request cleartext)
leg.response the origination leg's verified, decrypted response (Payload = response
cleartext; Status set when the recipient's app-level answer was a
relayed non-2xx, omitted for an ordinary 2xx response)
leg.failed the origination leg errored for a reason OTHER than a relayed
recipient response (Detail = error text)
ingress.received a Da Vinci ingress call arrived (LegType = route tag, Payload = request body)
ingress.responded the ingress call was answered (Detail = HTTP status, Payload = response body)
validate.result a $validate ran (Detail = "valid" | "invalid" | "validator unavailable")
sor.read the gateway read its data source (Op = SystemOfRecord method,
Detail = "found"/"not found"/coverage status, Payload = the
resource bytes for byte-returning reads)
type PayerDirectoryEntry ¶ added in v0.18.0
type PayerDirectoryEntry struct {
System string `json:"system"`
Value string `json:"value"`
HolderID string `json:"holderId"`
}
PayerDirectoryEntry is one row of the PAYER_DIRECTORY file.
func LoadPayerDirectory ¶ added in v0.18.0
func LoadPayerDirectory(path string) ([]PayerDirectoryEntry, error)
LoadPayerDirectory reads a JSON array of entries from path (the PAYER_DIRECTORY file).
type PayerRouter ¶ added in v0.18.0
type PayerRouter interface {
Resolve(p shnsdk.PayerIdentifier) (holderID string, ok bool)
}
PayerRouter resolves a Coverage.payor identity to a substrate holder id. ok=false ⇒ no mapping ⇒ the caller FAILS CLOSED. There is no default holder (AI-G11 / OWD-G10).
type PersonaRef ¶
type PersonaRef struct {
Key string // the JSON state key the UI reads (e.g. "coveredPci")
MemberID string // the persona member ID (e.g. "MBR-COVERED")
}
PersonaRef maps a console/UI state key to the demo persona member ID it resolves to. It is the single enumeration of the demo personas consumed by both internal/devstack (to seed the in-process Stack's PCI fields) and internal/holdersim (to serve GET /admin/state). The persona DATA lives in stubPersonas; this is only the ordered key↔member mapping, so the PCI is always derived via (SystemOfRecord).ResolvePatient — never a duplicated literal.
type PopulateContext ¶ added in v0.2.0
type PopulateContext struct {
Member string
PatientRef string // logical SHN ref ("Patient/<member>") — the QR subject downstream uses
// SubjectFHIRRef is the FHIR-store-resolvable Patient ref for the operated $populate subject
// (SoR.PatientFHIRRef — possibly a scoped id). Defaults to PatientRef. The native backend sends
// this as the subject; the consumer fence verifies the returned QR.subject against it, then
// normalizes QR.subject → PatientRef. The managed backend ignores it (it fills by PatientRef).
SubjectFHIRRef string
CoverageRef string
OrderRef string
Authored time.Time
}
PopulateContext carries the references + clock the population needs.
type Populator ¶ added in v0.2.0
type Populator interface {
Populate(ctx context.Context, packageJSON []byte, pc PopulateContext) (qrJSON []byte, fill []FilledItem, err error)
}
Populator produces a populated QuestionnaireResponse for a DTR leg. It is a PROVIDER-LOCAL connector seam (runs inside the holder's trust domain against the provider's data — NOT across a sealed Hub leg), selected by config. Backends:
- managedPopulator — in-house FillQuestionnaire (sandbox/demo green-keeper; default)
- nativePopulator — forward to an SDC Questionnaire/$populate endpoint (pass-through)
- (future) operated CQL engine — same interface, config-only drop-in
Populate takes the full $questionnaire-package (so a backend that needs the bundled Libraries/ValueSets can use them) and returns the populated QR JSON plus an OPTIONAL per-item fill summary (nil when the backend did not itself fill — e.g. a remote $populate engine did, so the gateway has no per-item attribution to surface).
type RelayError ¶ added in v0.27.0
type RelayError struct {
Status int
Body []byte
// ContentType is the framed answer's allowlisted Content-Type (empty when the
// frame carried none); origination/ingress relay writers use it verbatim.
ContentType string
}
RelayError carries a recipient's non-2xx application answer back up the origination call chain as a typed sentinel — mirroring errAuthorizationDenied (gateway.go). It is fed by roundTripInner decoding a frame-negotiated recipient's v1 message frame: a non-2xx frame status becomes this sentinel. Signatures stay ([]byte, error); every OriginateLeg caller's existing `if err != nil` guard aborts the exchange correctly, and the ingress handlers unwrap it (errors.As) to surface the recipient's real status + body.
func (*RelayError) Error ¶ added in v0.27.0
func (e *RelayError) Error() string
type Store ¶
type Store interface {
StoreAuthNumber(serviceRequestRef, preAuthRef string) error
AuthNumber(serviceRequestRef string) (string, bool)
RecordPendedClaim(subjectPCI, correlationID string) error
BeginClaimUpdate(subjectPCI, correlationID string) (bool, error)
ReleaseClaimUpdate(subjectPCI, correlationID string) error
FinalizeClaimUpdate(subjectPCI, correlationID string) error
RecordEOB(subjectPCI, eobID string, eobJSON []byte) error
EOBsForPatient(subjectPCI string) ([][]byte, bool)
EOBByID(eobID string) ([]byte, bool)
}
Store is the gateway's own durable business state (metadata/decision only — AI-1-compatible: the payer tracking its own claims/EOBs/auth-numbers, never a cross-holder clinical record). The partner does not implement this; today it is the in-memory stub (demo) or delegated to holdersim (separated stack); a gateway-owned Postgres implementation is a later edge slice.
type StubHolderData ¶
type StubHolderData struct {
// contains filtered or unexported fields
}
StubHolderData is the DEMO SystemOfRecord + Store implementation: a hermetic in-memory store with personas for UC-01 and the DTR/PAS slice. Its persona data (stubPersonas) is read-only/immutable demo data; the auth-number store is mutable and guarded by a mutex. Construct with NewStubHolderData.
A real HAPI-FHIR-backed (or DB) adapter plugs in behind the SystemOfRecord + Store seams with NO gateway change (purely additive); that production adapter is the deferred Phase-2 work.
func NewStubHolderData ¶
func NewStubHolderData() *StubHolderData
NewStubHolderData returns a ready-to-use StubHolderData with an initialized auth-number store and pended-claim ledger.
func (*StubHolderData) AuthNumber ¶
func (d *StubHolderData) AuthNumber(serviceRequestRef string) (string, bool)
AuthNumber returns a previously stored pre-auth number, or found=false. Safe for concurrent use.
func (*StubHolderData) BeginClaimUpdate ¶
func (d *StubHolderData) BeginClaimUpdate(subjectPCI, correlationID string) (bool, error)
BeginClaimUpdate ATOMICALLY claims a pended claim for a ClaimUpdate: if it is currently pended it transitions it to in-progress and returns true; otherwise (never pended, already approved, or another update already in progress) it returns false. This single test-and-set is the FR-6 current-state authority check AND the mutual-exclusion that serializes concurrent updates for the same claim — only one update can be in flight. The caller must pair it with FinalizeClaimUpdate (on approval) or ReleaseClaimUpdate (on any non-approval). Safe for concurrent use.
func (*StubHolderData) ClinicalContext ¶
func (d *StubHolderData) ClinicalContext(memberID string) (shnsdk.ClinicalContext, bool)
ClinicalContext returns the provider-LOCAL clinical context for a member. Members with no clinical data (not-covered, unknown) yield found=false.
func (*StubHolderData) CoverageInforce ¶
func (d *StubHolderData) CoverageInforce(memberID string) (inforce bool, reason string)
CoverageInforce answers whether the member's coverage is in force. Unknown members are treated as not in force.
func (*StubHolderData) EOBByID ¶
func (d *StubHolderData) EOBByID(eobID string) ([]byte, bool)
EOBByID returns one stored EOB by its id (read), or ok=false. Returns a defensive copy so a caller cannot mutate stored bytes. Safe for concurrent use.
func (*StubHolderData) EOBsForPatient ¶
func (d *StubHolderData) EOBsForPatient(subjectPCI string) ([][]byte, bool)
EOBsForPatient returns all stored EOBs for a patient PCI (search), or ok=false when none are stored. Returns defensive copies (a fresh slice of fresh byte slices) so a caller cannot mutate stored state. Safe for concurrent use.
func (*StubHolderData) FacilityRecords ¶
func (d *StubHolderData) FacilityRecords(memberID string) (map[string][]byte, bool)
FacilityRecords returns metro-spine's held records for MBR-UC05 (UC-05): the operative DiagnosticReport and its DocumentReference. All other members yield found=false. The provider does NOT hold these — they are retrieved by the consent-gated federated query (the non-aggregation showcase).
func (*StubHolderData) FinalizeClaimUpdate ¶
func (d *StubHolderData) FinalizeClaimUpdate(subjectPCI, correlationID string) error
FinalizeClaimUpdate completes the pended→approved transition: it removes the claim so a replayed update for it finds nothing (replay protection). Safe for concurrent use.
func (*StubHolderData) OpenCoverage ¶ added in v0.18.0
func (d *StubHolderData) OpenCoverage(memberID string) ([]byte, bool)
OpenCoverage returns the stub's modeled Coverage for the member (FR-G40): a US Core Coverage whose payor names the CMS payer Organization (shnsdk.CMSPayerIdentity) by DEFAULT, or the member's stubPayerOverrides entry when present (the hermetic multi-payer routing proof — MBR-PAYERB/MBR-PAYERUNKNOWN are the only members with an override; every other member is untouched, so all pre-existing hermetic origination stays byte-identical). Unknown members yield found=false.
func (*StubHolderData) OpenOrder ¶ added in v0.12.0
func (d *StubHolderData) OpenOrder(_ string) ([]byte, bool)
OpenOrder: the in-memory stub does not hold open orders; the provider-data lane requires a real FHIR SoR (FHIR_DATA_URL). Returns found=false.
func (*StubHolderData) PatientFHIRRef ¶ added in v0.2.0
func (d *StubHolderData) PatientFHIRRef(memberID string) (string, bool)
PatientFHIRRef — the in-memory stub uses logical refs (no FHIR store / scoped ids).
func (*StubHolderData) RecordEOB ¶
func (d *StubHolderData) RecordEOB(subjectPCI, eobID string, eobJSON []byte) error
RecordEOB stores a PA-decision EOB for a patient (keyed by subject PCI) and indexes it by EOB id for read-by-id. Stores a COPY of the bytes. Safe for concurrent use.
func (*StubHolderData) RecordPendedClaim ¶
func (d *StubHolderData) RecordPendedClaim(subjectPCI, correlationID string) error
RecordPendedClaim records a pended claim. Safe for concurrent use.
func (*StubHolderData) ReleaseClaimUpdate ¶
func (d *StubHolderData) ReleaseClaimUpdate(subjectPCI, correlationID string) error
ReleaseClaimUpdate returns an in-progress claim to pended (a ClaimUpdate did NOT approve — e.g. still insufficient or a validation error — so a later, complete amendment can still transition it). Safe for concurrent use.
func (*StubHolderData) Reset ¶
func (d *StubHolderData) Reset()
Reset clears all MUTABLE holder state — the auth-number store and the pended-claim ledger — back to clean synthetic state (the demo reset contract). The read-only persona fixtures are unaffected. Safe for concurrent use.
func (*StubHolderData) ResolveByReference ¶ added in v0.12.0
func (d *StubHolderData) ResolveByReference(_ string) ([]byte, bool)
ResolveByReference: the in-memory stub does not resolve FHIR references; the provider-data lane requires a real FHIR SoR (FHIR_DATA_URL). Returns found=false.
func (*StubHolderData) ResolvePatient ¶
func (d *StubHolderData) ResolvePatient(memberID string) (pci string, demo Demo, found bool)
ResolvePatient returns the member's PCI and demographics. Unknown members yield found=false.
func (*StubHolderData) StoreAuthNumber ¶
func (d *StubHolderData) StoreAuthNumber(serviceRequestRef, preAuthRef string) error
StoreAuthNumber records the payer-issued pre-auth number for a service request reference. Safe for concurrent use.
func (*StubHolderData) SupplementalReport ¶
func (d *StubHolderData) SupplementalReport(memberID string) ([]byte, bool)
SupplementalReport returns the provider-LOCAL supplemental DiagnosticReport for MBR-UC04 (UC-04, FR-32). All other members yield found=false. NOTE: MBR-UC05 deliberately yields false — the operative report is EXTERNAL (held by metro-spine), which is what forces the consent-gated federated query.
type SystemOfRecord ¶
type SystemOfRecord interface {
ResolvePatient(memberID string) (pci string, demo Demo, found bool)
// PatientFHIRRef returns the FHIR Patient reference ("Patient/<id>") as known to the
// backing FHIR store — the resolvable subject for an operated SDC Questionnaire/$populate
// (which reads the store directly and cannot resolve the logical member ref or an
// identifier-based subject). For a real FHIR SoR this is the store's (possibly scoped)
// resource id; the in-memory stub returns the logical "Patient/<member>". found=false ⇒
// the caller falls back to the logical ref.
PatientFHIRRef(memberID string) (ref string, found bool)
// CoverageInforce reads the US Core Coverage RECORD (CMS-0057: Coverage is a
// FHIR record on the Patient/Provider Access APIs). The eligibility
// DETERMINATION is the payer's decision — made by Adjudicator.Eligibility,
// which consults this record (the record-vs-determination split:
// the sandbox Adjudicator delegates straight here, so behavior is unchanged).
CoverageInforce(memberID string) (inforce bool, reason string)
ClinicalContext(memberID string) (shnsdk.ClinicalContext, bool)
SupplementalReport(memberID string) ([]byte, bool)
FacilityRecords(memberID string) (records map[string][]byte, found bool)
// OpenOrder returns the member's open order resource bytes (a ServiceRequest or
// DeviceRequest) for headless origination. found=false when none. The caller parses the
// product coding via shnsdk.ParseOrderProductCoding — the gateway never synthesizes the order.
OpenOrder(memberID string) (orderJSON []byte, found bool)
// OpenCoverage returns the member's in-force Coverage record bytes (the payer-of-record
// resource) for headless origination — the routing identity and the wire payload both
// derive from it (FR-G40). found=false when none.
OpenCoverage(memberID string) (coverageJSON []byte, found bool)
// ResolveByReference returns the bytes of a resource named by a relative reference
// (e.g. "Organization/dme-1") from the FHIR SoR. found=false when absent. Used to resolve
// an order's performer (the DME supplier Organization) for headless order-dispatch origination.
ResolveByReference(ref string) (resourceJSON []byte, found bool)
}
SystemOfRecord is the read seam over the holder's backing system of record (FR-1). The provider side resolves members and reads provider-LOCAL clinical context; the payer side reads coverage status; the facility side serves targeted records; the PHG side reads patient demographics for the patient surface. Edge slice E2 implements this as a FHIR/SMART-Backend-Services client; today it is the stub personas (demo) or the holdersim network client (separated stack).
Source Files
¶
- adjudicator.go
- composite.go
- connector.go
- crd_dispatch_native.go
- crd_native.go
- davincimap.go
- exchange_ir.go
- exchangestore.go
- fhirread.go
- fhirref.go
- gateway.go
- holderdata.go
- inbound.go
- ingress.go
- ingress_crd.go
- ingress_discovery.go
- ingress_dtr.go
- ingressauth.go
- legresponder.go
- native.go
- nativepas.go
- nativepopulate.go
- observer.go
- order_build.go
- originate.go
- originate_codes.go
- originate_homeoxygen.go
- originate_resume.go
- pas_native.go
- pas_tail.go
- patientaccess.go
- payer.go
- payerrouter.go
- personas.go
- populator.go
- relayresp.go
- uc04_attest.go
- workstream_pa.go