@crvouga/mockingbird-service-junction 3.6.1 → 3.7.0
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.
- package/CHANGELOG.md +10 -0
- package/README.md +206 -7
- package/SUPPORT.md +4 -2
- package/dist/{chunk-VHVGQ3WX.js → chunk-27N4VA23.js} +1039 -274
- package/dist/chunk-27N4VA23.js.map +7 -0
- package/dist/{chunk-HJJCEIVH.js → chunk-NTGGNJKR.js} +137 -17
- package/dist/chunk-NTGGNJKR.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +317 -107
- package/dist/index.js +1 -1
- package/dist/server.d.ts +347 -96
- package/dist/server.js +2 -2
- package/openapi.yaml +207 -0
- package/package.json +1 -1
- package/dist/chunk-HJJCEIVH.js.map +0 -7
- package/dist/chunk-VHVGQ3WX.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-junction
|
|
2
2
|
|
|
3
|
+
## 3.7.0 (2026-10-19)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- resolve the agent-reported issue queue in one batch ([25c52b6](https://github.com/crvouga/mockingbird/commit/25c52b668a53ddb80b968419601a20abf33f956b))
|
|
8
|
+
|
|
9
|
+
### Fixes and improvements
|
|
10
|
+
|
|
11
|
+
- record reported production refusal for delegated explicit client_bill ([3525699](https://github.com/crvouga/mockingbird/commit/35256996166f4f8ddcf25f16b7fcca2ca72c1a38))
|
|
12
|
+
|
|
3
13
|
## 3.6.1 (2026-10-18)
|
|
4
14
|
|
|
5
15
|
### Fixes and improvements
|
package/README.md
CHANGED
|
@@ -56,7 +56,11 @@ npx mockingbird-junction serve --help
|
|
|
56
56
|
| `--port <n>` | `8787` | Port to listen on (`0` for any free port; the bound URL is printed) |
|
|
57
57
|
| `--host <host>` | `127.0.0.1` | Interface to bind |
|
|
58
58
|
| `--corpus <default\|none\|file>` | `default` | The shipped corpus, no corpus (synthetic data), or a file from `corpus pull` |
|
|
59
|
-
| `--geo <corpus\|synthetic>` | `corpus` with a corpus | How unknown ZIPs are answered; see [Geo](#geo-corpus-or-synthetic) |
|
|
59
|
+
| `--geo <corpus\|synthetic\|corpus+synthetic>` | `corpus` with a corpus | How unknown ZIPs are answered; see [Geo](#geo-corpus-or-synthetic) |
|
|
60
|
+
| `--zip-overlays <file>` | — | [ZIP aliases and per-ZIP overrides](#hybrid-geo-and-zip-overlays) |
|
|
61
|
+
| `--catalog-overlays <file>` | — | [Lab tests derived from catalog ones](#catalog-overlays-and-a-la-carte-markers) at boot |
|
|
62
|
+
| `--marker-catalog <file>` | — | Markers `GET /v3/lab_tests/markers` offers, with [pricing](#catalog-overlays-and-a-la-carte-markers) |
|
|
63
|
+
| `--add-on-source-markers` | off | Name the markers behind each add-on result line |
|
|
60
64
|
| `--lab-accounts <file>` | built-in fixtures | [Lab accounts](#lab-accounts): a JSON array, or `{ "presets": [...], "accounts": [...] }` |
|
|
61
65
|
| `--team-id <uuid>` | the corpus's team | The [team](#team-identity) the emulator answers as |
|
|
62
66
|
| `--max-users <n>` | unlimited | Enforce the sandbox's [live-user cap](#sandbox-limits) |
|
|
@@ -245,10 +249,11 @@ Every Mockingbird service answers the same control surface, outside the vendor's
|
|
|
245
249
|
| `GET` / `POST` / `DELETE /__admin/faults` | List, add or clear [fault rules](#faults-and-error-shapes) (`DELETE ?id=` removes one) |
|
|
246
250
|
| `POST /__admin/faults/presets/{name}` | Add a named Junction fault; body may override `count`, `rate`, `operationId`… |
|
|
247
251
|
| `GET /__admin/metrics` | Requests by operation and status, fault count, and **unmatched routes** |
|
|
248
|
-
| `GET /__admin/orders` | Orders in the namespace with their current status
|
|
252
|
+
| `GET /__admin/orders` | Orders in the namespace with their current status, the `lab_account_id` each was placed with (`null`: Junction's platform account) and `lab_account_request` (below) |
|
|
249
253
|
| `POST /__admin/orders/{id}/transition` | Move an order: `{ "to": "completed", "result": "abnormal" }` ([order control](#order-control)) |
|
|
250
254
|
| `GET` / `PUT /__admin/results/{id}` | Read or install an exact result payload / PDF for an order |
|
|
251
255
|
| `GET /__admin/result-fixtures` | The named results |
|
|
256
|
+
| `GET` / `PUT /__admin/quirks` | Read or replace the namespace's opt-in [sandbox quirks](#sandbox-quirks) (`{ "quirks": { "sameSecondCancelStatus": true } }`) |
|
|
252
257
|
| `GET` / `PUT /__admin/lab-accounts` | Read or replace the namespace's [lab accounts](#lab-accounts) (`{ "accounts": [...], "presets": [...] }`; `{ "accounts": null }` restores the default) |
|
|
253
258
|
| `POST /__admin/lab-accounts` | Add one account; 409 if the id exists |
|
|
254
259
|
| `PATCH` / `DELETE /__admin/lab-accounts/{id}` | Merge fields into an account (`{ "status": "suspended" }`, `{ "states": [...] }`) / remove it; 404 if absent |
|
|
@@ -328,6 +333,92 @@ a radius with no recording, or any read with parameters the corpus did not recor
|
|
|
328
333
|
`--geo synthetic` the derivation still applies, and only reads with nothing to derive from are
|
|
329
334
|
invented.
|
|
330
335
|
|
|
336
|
+
### Hybrid geo and ZIP overlays
|
|
337
|
+
|
|
338
|
+
`--geo corpus+synthetic` (`geo: "corpus+synthetic"`) replays the recording for the ZIPs the corpus
|
|
339
|
+
covers and synthesizes every other ZIP, so a suite needs no second, synthetic runtime as a
|
|
340
|
+
fallback. A covered ZIP is still never answered next to its recording: a read the recording cannot
|
|
341
|
+
answer (see above) refuses with the same 424 as `--geo corpus`. Switch it per namespace with
|
|
342
|
+
`PUT /__admin/geo {"mode": "corpus+synthetic"}`.
|
|
343
|
+
|
|
344
|
+
`zipOverlays` (`--zip-overlays <file>`, or `PUT /__admin/geo {"overlays": {...}}`) edits answers
|
|
345
|
+
for individual ZIPs, in any geo mode:
|
|
346
|
+
|
|
347
|
+
```json
|
|
348
|
+
{
|
|
349
|
+
"aliases": { "07105": "85004" },
|
|
350
|
+
"overrides": { "07105": { "phlebotomy_served": true }, "10118": { "no_pscs": true } }
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
An alias makes a ZIP answer as another one (coverage, recordings and the synthetic model all use
|
|
355
|
+
the target; the response echoes the requested ZIP). `phlebotomy_served` sets
|
|
356
|
+
`phlebotomy.is_served` (and `providers`) on `area/info`; `no_pscs` empties the `psc/info` list and
|
|
357
|
+
zeroes the `within_radius` counts on `area/info`. An override is looked up by the requested ZIP,
|
|
358
|
+
then by its alias target. Overlays are configuration: they survive `reset()`.
|
|
359
|
+
|
|
360
|
+
The sealed sandbox recording agrees with the report behind this feature that NJ `07030` is not
|
|
361
|
+
served for at-home phlebotomy, and the synthetic model reports `10118`, `11201`, `12207`, `07030`
|
|
362
|
+
and `07601` as not served. It does not know that NJ `07105` is served (the synthetic model only
|
|
363
|
+
serves a handful of ZIP prefixes), so set that one with an override.
|
|
364
|
+
|
|
365
|
+
## Catalog overlays and a-la-carte markers
|
|
366
|
+
|
|
367
|
+
**Catalog overlays** (`catalogOverlays`, `--catalog-overlays <file>`) add lab tests derived from
|
|
368
|
+
ones the catalog already holds, with no network access, to every namespace at boot and again on
|
|
369
|
+
every `reset()`:
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
import { createRuntime } from "@crvouga/mockingbird-service-junction"
|
|
373
|
+
|
|
374
|
+
createRuntime({
|
|
375
|
+
catalogOverlays: [
|
|
376
|
+
{
|
|
377
|
+
from: "lipid_panel_athome", // id or slug of a catalog lab test (or an earlier overlay)
|
|
378
|
+
id: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
|
|
379
|
+
name: "Lipid Panel: Quest",
|
|
380
|
+
slug: "lipid_panel_quest", // default: derived from name
|
|
381
|
+
lab: "sonora_quest", // a lab slug the catalog lists, or a lab record { id, slug, name, ... }
|
|
382
|
+
stripAoe: true, // markers lose their ask-on-order questions
|
|
383
|
+
autoGenerated: true, // lists with generation_method=auto, not by default
|
|
384
|
+
},
|
|
385
|
+
],
|
|
386
|
+
})
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
`method`, `price` (dollars) and `status` can be overridden too. Moving the clone to a lab gives its
|
|
390
|
+
markers and expected results that lab's id. A bad overlay (unknown `from`, non-UUID or duplicate
|
|
391
|
+
`id`, unknown `lab`) fails at boot naming `catalogOverlays[n].<field>`.
|
|
392
|
+
|
|
393
|
+
**A-la-carte markers.** `GET /v3/lab_tests/markers` lists the markers a team can order one by one:
|
|
394
|
+
those embedded in active catalog lab tests, plus `markerCatalog` entries (`--marker-catalog
|
|
395
|
+
<file>`) with their own `price`, `pricing`, `aoe`, `expected_results` and `a_la_carte_enabled`. It
|
|
396
|
+
takes `lab_id`, `lab_slug` (wins over `lab_id`), `name` (a name substring, or a provider test code),
|
|
397
|
+
`a_la_carte_enabled`, `lab_account_id` (narrows to the account's lab), `include_pricing`, `page` and
|
|
398
|
+
`size`, and answers `{ markers, total, page, size, pages }` (plus `pricing: { currency, data }` keyed
|
|
399
|
+
by marker id for the page's markers with `include_pricing=true`). A marker price is read as dollars
|
|
400
|
+
(`"12.50"` is `base_amount_minor: 1250`); `"N/A"` is `{ "unspecified": "price_unavailable" }`.
|
|
401
|
+
|
|
402
|
+
`POST /v3/lab_test/estimate_order_set_pricing` prices each order set (`lab_test_ids` and/or
|
|
403
|
+
`add_on.marker_ids` / `provider_ids`) as one `lab_charge` component: the sum of the lab tests'
|
|
404
|
+
`price` and the add-on markers' prices, with a `marker_breakdown` for add-ons. If any add-on marker
|
|
405
|
+
has no stated price the whole estimate is `price_unavailable`. `modality`, `us_state` and `billing`
|
|
406
|
+
are validated but do not change the price, and no other charge components are modelled.
|
|
407
|
+
|
|
408
|
+
Both routes follow the published contract
|
|
409
|
+
([markers](https://docs.junction.com/api-reference/lab-testing/biomarkers),
|
|
410
|
+
[estimate](https://docs.junction.com/api-reference/lab-testing/estimate-order-set-pricing)); neither
|
|
411
|
+
has been compared with the live sandbox (prices are contract-owned), so their parity is disabled and
|
|
412
|
+
the 400 messages for unknown tests/markers are borrowed from `create_order`.
|
|
413
|
+
|
|
414
|
+
`addOnSourceMarkers: true` (`--add-on-source-markers`) makes each biomarker line of an add-on order
|
|
415
|
+
carry `source_markers: [{ marker_id, name, slug, provider_id }]`. It is off by default, because the
|
|
416
|
+
default result lines carry no `source_markers`, and was reported from a sandbox probe that has not
|
|
417
|
+
been re-verified.
|
|
418
|
+
|
|
419
|
+
`GET /v3/lab_tests` lists every lab test unless filtered; pass `status=active` to exclude inactive
|
|
420
|
+
ones. The documented default of that filter is not stated, so the emulator does not change it.
|
|
421
|
+
|
|
331
422
|
## Lab accounts
|
|
332
423
|
|
|
333
424
|
`create_order` selects explicit linked accounts in either `active` or `ready_to_launch`
|
|
@@ -445,8 +536,21 @@ but NJ, NY and RI (47).
|
|
|
445
536
|
| `bioreference_platform` | `bioreference` | `not_delegated` | `client_bill`: `PLATFORM_ACCOUNT_STATES` | `[]` | recorded ("Junction BioReference Account") |
|
|
446
537
|
| `bioreference_patient_bill_passthrough` | `bioreference` | `not_delegated` | `patient_bill_passthrough`: NJ, NY | the team | recorded |
|
|
447
538
|
| `quest_platform` / `labcorp_platform` | `quest` / `labcorp` | `not_delegated` | `client_bill`: `PLATFORM_ACCOUNT_STATES` | `[]` | recorded ("Junction Quest/Labcorp Account") |
|
|
539
|
+
| `bioreference_current_platform` | `bioreference` | `not_delegated` | `patient_bill_passthrough`: NJ, NY | `[]` | team listing reported 2026-10-18 (#475) |
|
|
540
|
+
| `quest_sandbox_platform` | `quest` | `not_delegated` | `client_bill`: `PLATFORM_ACCOUNT_STATES`; `commercial_insurance`: all 50 | `[]` | sandbox listing reported 2026-10-18 (#475) |
|
|
541
|
+
| `sonora_quest_production_platform` | `sonora_quest` | `not_delegated` | `client_bill`: `PLATFORM_ACCOUNT_STATES` | `[]` | production listing reported 2026-10-18 (#475) |
|
|
448
542
|
| `suspended_bioreference` / `suspended_quest` / `suspended_labcorp` | as above | `not_delegated` | as the platform accounts | `[]` | the platform shapes with `status: "suspended"` |
|
|
449
543
|
|
|
544
|
+
The September recording's `bioreference_platform` is **illustrative, not a current listing**: the
|
|
545
|
+
house BioReference account now lists only `patient_bill_passthrough` for NJ and NY (use
|
|
546
|
+
`bioreference_current_platform`, and see
|
|
547
|
+
[omitted house-account billing](#omitted-house-account-billing-467) for how production still
|
|
548
|
+
accepts `client_bill` when no account is named). No account at any lab lists DC, so no preset does
|
|
549
|
+
either. `bioreference_current_platform`, `quest_sandbox_platform` and `sonora_quest_production_platform`
|
|
550
|
+
follow listings an agent
|
|
551
|
+
reported from `GET /v3/lab_test/lab_account` (a consumer-audit report with synthetic ids, not a
|
|
552
|
+
repository probe); the older presets keep their shapes so pinned suites do not change.
|
|
553
|
+
|
|
450
554
|
Every preset is `status: "active"` unless named `suspended_*`. `GET /__admin/lab-accounts/presets`
|
|
451
555
|
returns the full records, the deprecated `aliases`, and the `synthetic` presets (not a recorded
|
|
452
556
|
account). `bioreference_customer_multi_state` is a deprecated alias of `bioreference_platform`: it
|
|
@@ -584,6 +688,8 @@ valid choices, never approximated. `result` picks a named result — `normal`, `
|
|
|
584
688
|
shape. For an exact payload, `PUT /__admin/results/{id}` with `{ "results": [...],
|
|
585
689
|
"missing_results": null, "interpretation": "critical", "pdf_base64": "…" }`.
|
|
586
690
|
|
|
691
|
+
**Same-second cancel.** See the opt-in [sandbox quirks](#sandbox-quirks).
|
|
692
|
+
|
|
587
693
|
There is no `isTestCancelled` in Junction's contract; cancelling produces the vendor's
|
|
588
694
|
`cancelled.<method>.cancelled` event and webhook, which is what a consumer derives that flag from.
|
|
589
695
|
|
|
@@ -630,6 +736,23 @@ so one worker's injected failure never lands on another's request; one added in-
|
|
|
630
736
|
applies to every namespace unless given a `namespace`. Over HTTP: `POST /__admin/faults` with the same fields, or
|
|
631
737
|
`POST /__admin/faults/presets/sandbox_user_quota`.
|
|
632
738
|
|
|
739
|
+
A rule can also match on the request itself: `path`, `pathPattern`, `requestHeaders`, `query`, and
|
|
740
|
+
`requestBody`, a map from a dotted path in the JSON body to the value it must equal. That targets
|
|
741
|
+
one member when the backend sends no namespace header, with an optional `body` to answer with:
|
|
742
|
+
|
|
743
|
+
```bash
|
|
744
|
+
# Refuse one member's order
|
|
745
|
+
curl -X POST localhost:8787/__admin/faults -d '{"method":"POST","path":"/v3/order",
|
|
746
|
+
"requestBody":{"patient_details.email":"member-a@example.test"},"status":503}'
|
|
747
|
+
# No phlebotomy slots for one ZIP code
|
|
748
|
+
curl -X POST localhost:8787/__admin/faults -d '{"method":"POST",
|
|
749
|
+
"pathPrefix":"/v3/order/phlebotomy/appointment/availability",
|
|
750
|
+
"requestBody":{"zip_code":"00000"},"status":200,"body":{"slots":[],"timezone":"America/Phoenix"}}'
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
A body that is missing, not JSON, or not a JSON object never matches. See the
|
|
754
|
+
[fault rule reference](../../../docs/admin-controls/FAULTS.md#match-on-the-request-body).
|
|
755
|
+
|
|
633
756
|
## Webhooks
|
|
634
757
|
|
|
635
758
|
With `webhooks` / `--webhook-url`, every event is delivered signed, with retries:
|
|
@@ -730,7 +853,7 @@ Main entry (`@crvouga/mockingbird-service-junction`, runtime-neutral):
|
|
|
730
853
|
|
|
731
854
|
| Export | Description |
|
|
732
855
|
| --- | --- |
|
|
733
|
-
| `createRuntime` | `(options?: JunctionRuntimeOptions) => JunctionRuntime` — the served emulator (health, admin, namespaces, clock, faults, metrics, journal, webhooks) as one `fetch`. Options: `corpus`, `geo`, `labAccounts`, `teamId`, `limits`, `identity`, `defaultBillingTypes`, `fixtures`, `journalSize`, `webhooks`, `onWebhook`, `sqlite`, `clock`, `seed`, `adminKey`, `onLog`. |
|
|
856
|
+
| `createRuntime` | `(options?: JunctionRuntimeOptions) => JunctionRuntime` — the served emulator (health, admin, namespaces, clock, faults, metrics, journal, webhooks) as one `fetch`. Options: `corpus`, `geo`, `zipOverlays`, `catalogOverlays`, `markerCatalog`, `addOnSourceMarkers`, `labAccounts`, `teamId`, `limits`, `identity`, `defaultBillingTypes`, `labAccountBehavior`, `quirks`, `fixtures`, `journalSize`, `webhooks`, `onWebhook`, `sqlite`, `clock`, `seed`, `adminKey`, `onLog`. |
|
|
734
857
|
| `JunctionAPI` | Class. `new JunctionAPI(options?)`: one namespace's emulator, implementing `fetch(request: Request): Promise<Response>`. |
|
|
735
858
|
| `JUNCTION_NAMESPACE` | `"junction"` — the default namespace's storage key when sharing a `sqlite` client. |
|
|
736
859
|
| `document` | The vendored Junction OpenAPI document (Mockingbird subset) that drives routing. |
|
|
@@ -801,7 +924,8 @@ Main entry (`@crvouga/mockingbird-service-junction`, runtime-neutral):
|
|
|
801
924
|
| `reset()` | `Promise<void>` — clear state; re-install the corpus or default catalog, and the configured lab accounts. |
|
|
802
925
|
| `installCorpus(corpus)` | Install a `SealedCorpus`: observations (shared, read-only), catalog, labs, lab accounts, ZIP coverage. |
|
|
803
926
|
| `corpusInfo()` | `CorpusInfo \| undefined` — label, recording date, source and counts. |
|
|
804
|
-
| `geoMode` | `"corpus" \| "synthetic"`, settable. |
|
|
927
|
+
| `geoMode` | `"corpus" \| "synthetic" \| "corpus+synthetic"`, settable. |
|
|
928
|
+
| `zipOverlays` | [ZIP aliases and overrides](#hybrid-geo-and-zip-overlays) for this namespace; settable, kept across `reset()`. |
|
|
805
929
|
| `configureLabAccounts(layout?)` / `labAccounts()` | Replace (a list, or `{ presets, accounts }`; `undefined` restores the default) / read the team's lab accounts. |
|
|
806
930
|
| `addLabAccount(input)` / `addLabAccountPreset(name, id?)` / `patchLabAccount(id, patch)` / `removeLabAccount(id)` | Change one account; kept across `reset()`. |
|
|
807
931
|
| `teamId` | The team this namespace answers as. |
|
|
@@ -828,7 +952,11 @@ type JunctionAPIOptions = {
|
|
|
828
952
|
namespace?: string // storage namespace; default "junction"
|
|
829
953
|
now?: () => number // clock in ms; default Date.now
|
|
830
954
|
corpus?: SealedCorpus // installed now and on every reset()
|
|
831
|
-
geo?: "corpus" | "synthetic" // default "corpus" with a corpus, else "synthetic"
|
|
955
|
+
geo?: "corpus" | "synthetic" | "corpus+synthetic" // default "corpus" with a corpus, else "synthetic"
|
|
956
|
+
zipOverlays?: { aliases?: Record<string, string>; overrides?: Record<string, { phlebotomy_served?: boolean; no_pscs?: boolean }> }
|
|
957
|
+
catalogOverlays?: CatalogOverlay[] // lab tests cloned from catalog ones, now and on every reset()
|
|
958
|
+
markerCatalog?: MarkerCatalogEntry[] // markers GET /v3/lab_tests/markers offers on top of the catalog's
|
|
959
|
+
addOnSourceMarkers?: boolean // add-on result lines carry source_markers; default false
|
|
832
960
|
labAccounts?: LabAccountInput[] | { presets?: (string | { name; id? })[]; accounts?: LabAccountInput[] }
|
|
833
961
|
teamId?: string // default: the corpus's recorded team, else MOCK_TEAM_ID
|
|
834
962
|
limits?: { maxUsers?: number | null; simulateRequiresSandbox?: boolean; rateLimitPerSecond?: number | null }
|
|
@@ -940,8 +1068,11 @@ const runtime = createRuntime({
|
|
|
940
1068
|
})
|
|
941
1069
|
```
|
|
942
1070
|
|
|
943
|
-
These controls encode the independently reported
|
|
944
|
-
|
|
1071
|
+
These controls encode the independently reported observations in #440/#441. For #440 the
|
|
1072
|
+
reporter states that production returns the same refusal for a delegated BioReference
|
|
1073
|
+
account with explicit `client_bill` ("Lab 14 ..." there, "Lab 13 ..." in the sandbox);
|
|
1074
|
+
that is a reported observation, not a repository probe, and the vendor has not explained it,
|
|
1075
|
+
so no billing rule is built in. Exceptions apply only to explicit
|
|
945
1076
|
root account IDs and explicit billing. `defaultBillingTypes` still governs omitted
|
|
946
1077
|
billing independently. `GET/PUT /__admin/lab-account-behavior` inspect/change one
|
|
947
1078
|
namespace's policy; changes survive its reset and never affect another namespace.
|
|
@@ -964,3 +1095,71 @@ until the combined-panel semantics are verified. Malformed add-ons also refuse w
|
|
|
964
1095
|
an order; requested add-on markers are never silently discarded.
|
|
965
1096
|
Panel and custom orders share account/billing checks for home and walk-in collection.
|
|
966
1097
|
The native profile keeps its existing panel-only contract.
|
|
1098
|
+
|
|
1099
|
+
### Observed profile and oracle label
|
|
1100
|
+
|
|
1101
|
+
`profile: "observed"` with `oracle: "sandbox" | "production"` is the general form of
|
|
1102
|
+
`sandbox-observed` (an alias that always reports `oracle: "sandbox"`), so
|
|
1103
|
+
`GET /__admin/lab-account-behavior` says which vendor environment a configuration reproduces.
|
|
1104
|
+
Account-owned `rejectBilling` / `allowBilling` observations apply to either oracle, per
|
|
1105
|
+
account and never as a blanket delegated-account rule: a delegated customer account refuses
|
|
1106
|
+
explicit `client_bill` only when its own entry says so. The October 2026 sandbox omission
|
|
1107
|
+
recordings (#439) are sandbox observations, so they apply only to `oracle: "sandbox"`; with
|
|
1108
|
+
`oracle: "production"` an omitted account selects the house account as `expected-contract`
|
|
1109
|
+
does. Whether production also refuses a delegated account when `billing_type` is omitted is
|
|
1110
|
+
unverified, so it is not modelled. `oracle` on any other profile, or `production` on the
|
|
1111
|
+
`sandbox-observed` alias, is refused.
|
|
1112
|
+
|
|
1113
|
+
### Omitted house-account billing (#467)
|
|
1114
|
+
|
|
1115
|
+
A reporter observed production accepting an AZ `client_bill` order with no `lab_account_id` on
|
|
1116
|
+
a team whose house BioReference account lists only `patient_bill_passthrough` for NY and NJ,
|
|
1117
|
+
placing it on the house account (its requisition prints the house account number). That is a
|
|
1118
|
+
single consumer report, not a repository probe, so the default is unchanged (the listing is
|
|
1119
|
+
enforced). Opt in per lab:
|
|
1120
|
+
|
|
1121
|
+
```ts
|
|
1122
|
+
import { createRuntime } from "@crvouga/mockingbird-service-junction"
|
|
1123
|
+
|
|
1124
|
+
createRuntime({
|
|
1125
|
+
labAccountBehavior: {
|
|
1126
|
+
profile: "expected-contract",
|
|
1127
|
+
omittedAccountBilling: { bioreference: "unchecked" },
|
|
1128
|
+
},
|
|
1129
|
+
})
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
With `unchecked`, an order whose **root** `lab_account_id` is omitted (a nested-only id is
|
|
1133
|
+
ignored) and that resolves to a Junction-owned account (`org_id: null`) skips that account's
|
|
1134
|
+
listed billing and state check. The order keeps the house account's identity on POST, GET and
|
|
1135
|
+
the requisition. Explicit selection of the house account keeps its listed policy (or an
|
|
1136
|
+
account-owned `rejectBilling`), and a customer-owned account chosen by routing keeps its own
|
|
1137
|
+
listing. `GET/PUT /__admin/lab-account-behavior` read and change `omittedAccountBilling`.
|
|
1138
|
+
|
|
1139
|
+
### Where an order's account id was sent (#473)
|
|
1140
|
+
|
|
1141
|
+
`GET /__admin/orders` adds `lab_account_request: { labAccountId, nestedLabAccountId }` per order
|
|
1142
|
+
(`instance().orderLabAccountRequest(id)`): the id carried at the request root, which selects
|
|
1143
|
+
the account, and the one nested in `order_set`, which Junction ignores. Each is `null` when
|
|
1144
|
+
absent. The request body itself is still not stored; orders seeded by a fixture have
|
|
1145
|
+
`lab_account_request: null`.
|
|
1146
|
+
|
|
1147
|
+
### Sandbox quirks
|
|
1148
|
+
|
|
1149
|
+
Behaviors the sandbox shows that clients must tolerate, every one off by default
|
|
1150
|
+
(`createRuntime({ quirks })`, or per namespace `GET/PUT /__admin/quirks`; they survive `reset()`).
|
|
1151
|
+
|
|
1152
|
+
| Quirk | Effect |
|
|
1153
|
+
| --- | --- |
|
|
1154
|
+
| `sameSecondCancelStatus` (#474) | `POST /v3/order/{id}/cancel` in the same wall-clock second as the order's creation records a `cancelled.<method>.cancelled` event with the same timestamp, but `status`, `last_event` and `updated_at` stay `received`; a repeat cancel is a no-op. A cancel at least one second later reads back `cancelled`. |
|
|
1155
|
+
|
|
1156
|
+
This was reported from the sandbox (not re-measured here, production unverified). The quirk does
|
|
1157
|
+
not publish a webhook or cascade-cancel appointments for the stale cancel; the report does not say
|
|
1158
|
+
what the vendor does there.
|
|
1159
|
+
|
|
1160
|
+
### Requisition text layout (#464)
|
|
1161
|
+
|
|
1162
|
+
The synthetic requisition PDF prints two text lines: `Requisition <order id>` and
|
|
1163
|
+
`Account number: <provider number>` (`unknown` when the order has no frozen number), so an
|
|
1164
|
+
extractor that accepts a field label only at the start of a line finds it. The layout is for
|
|
1165
|
+
interoperability, not vendor pixel fidelity.
|
package/SUPPORT.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Generated from `openapi.yaml`; do not edit by hand.
|
|
4
4
|
|
|
5
|
-
- operations in spec: **
|
|
6
|
-
- supported by the emulator: **
|
|
5
|
+
- operations in spec: **42**
|
|
6
|
+
- supported by the emulator: **42**
|
|
7
7
|
- parity enabled: **22**
|
|
8
8
|
|
|
9
9
|
| operationId | route | emulator | parity | notes |
|
|
@@ -17,10 +17,12 @@ Generated from `openapi.yaml`; do not edit by hand.
|
|
|
17
17
|
| `patch_user_info_v2_user__user_id__info_patch` | `PATCH /v2/user/{user_id}/info` | ✅ supported | ✅ | |
|
|
18
18
|
| `get_latest_user_info_user_v2_user__user_id__info_latest_get` | `GET /v2/user/{user_id}/info/latest` | ✅ supported | ✅ | |
|
|
19
19
|
| `get_paginated_lab_tests_for_team_v3_lab_test_get` | `GET /v3/lab_test` | ✅ supported | ✅ | |
|
|
20
|
+
| `estimate_order_set_pricing_v3_lab_test_estimate_order_set_pricing_post` | `POST /v3/lab_test/estimate_order_set_pricing` | ✅ supported | ❌ disabled | prices are contract-owned; the emulator prices from the configured catalog (lab test price, marker price) and models the documented shape only |
|
|
20
21
|
| `get_team_lab_accounts_v3_lab_test_lab_account_get` | `GET /v3/lab_test/lab_account` | ✅ supported | ❌ disabled | lab-account inventory is fixture-owned; the emulator models the documented shape, filters and routing rules, not a live account inventory |
|
|
21
22
|
| `get_lab_tests_for_team_v3_lab_tests_get` | `GET /v3/lab_tests` | ✅ supported | ✅ | |
|
|
22
23
|
| `get_lab_test_for_team_v3_lab_tests__lab_test_id__get` | `GET /v3/lab_tests/{lab_test_id}` | ✅ supported | ✅ | |
|
|
23
24
|
| `get_labs_v3_lab_tests_labs_get` | `GET /v3/lab_tests/labs` | ✅ supported | ✅ | |
|
|
25
|
+
| `get_markers_v3_lab_tests_markers_get` | `GET /v3/lab_tests/markers` | ✅ supported | ❌ disabled | the marker inventory is the team's catalog (and any configured marker catalog); prices and availability are account-owned, so the emulator models the documented shape and filters, not a live inventory |
|
|
24
26
|
| `get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get` | `GET /v3/lab_tests/{lab_test_id}/markers` | ✅ supported | ✅ | |
|
|
25
27
|
| `list_order_set_markers_v3_lab_tests_list_order_set_markers_post` | `POST /v3/lab_tests/list_order_set_markers` | ✅ supported | ✅ | |
|
|
26
28
|
| `create_order_v3_order_post` | `POST /v3/order` | ✅ supported | ✅ | Native profile parity only; explicit account profiles add fixture-owned billing policies and custom-marker orders, without production parity certification. |
|