@crvouga/mockingbird-service-junction 3.6.0 → 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 CHANGED
@@ -1,6 +1,22 @@
1
1
  # Changelog — @crvouga/mockingbird-service-junction
2
2
 
3
- ## 3.6.0 (2026-10-17)
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
+
13
+ ## 3.6.1 (2026-10-18)
14
+
15
+ ### Fixes and improvements
16
+
17
+ - sandbox-observed omission controls place orders on the platform account ([c9146ea](https://github.com/crvouga/mockingbird/commit/c9146eae3c867dcfee1ef00053288cd5407b5e9c))
18
+
19
+ ## 3.6.0 (2026-10-16)
4
20
 
5
21
  ### Features
6
22
 
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 and the `lab_account_id` each was placed with (`null`: Junction's platform account) |
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,14 +1068,25 @@ const runtime = createRuntime({
940
1068
  })
941
1069
  ```
942
1070
 
943
- These controls encode the independently reported sandbox observations in #440/#441;
944
- they do not establish production billing behavior. Exceptions apply only to explicit
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.
948
1079
  Unknown profile names are rejected. CLI/server equivalents are `--lab-account-profile`
949
1080
  and `--lab-account-sandbox-policies <json-file>` (the account-policy object).
950
1081
 
1082
+ `sandbox-observed` also encodes the owner-recorded October 2026 sandbox omission controls
1083
+ (#439), which are recorded observations, not a live repository probe: an order whose
1084
+ **root** `lab_account_id` is omitted, nested only in `order_set`, or an unknown UUID is
1085
+ placed on the lab's platform account (`lab_account_id: null` on POST and GET, no listed
1086
+ `allowed_billing` check), while a root ID naming a listed account keeps its identity and
1087
+ policy. `expected-contract` keeps the strict behavior (unknown ID → 400, omission → the
1088
+ house account).
1089
+
951
1090
  The explicit profiles also accept `order_set.add_on` with `provider_ids` or `marker_ids`
952
1091
  from one lab's configured marker catalog. The selected markers determine the synthetic
953
1092
  custom panel; unresolved or cross-lab combinations refuse without placing an order.
@@ -956,3 +1095,71 @@ until the combined-panel semantics are verified. Malformed add-ons also refuse w
956
1095
  an order; requested add-on markers are never silently discarded.
957
1096
  Panel and custom orders share account/billing checks for home and walk-in collection.
958
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: **40**
6
- - supported by the emulator: **40**
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. |