@whooshbang/contracts 2.0.0-rc.4 → 2.0.0-rc.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/contract-manifest.json +32 -32
  3. package/dist/generated/artifact-index.d.ts +33 -33
  4. package/dist/generated/artifact-index.js +32 -32
  5. package/dist/generated/validators-standalone.js +660 -351
  6. package/dist/generated/validators-standalone.js.map +1 -1
  7. package/dist/generated/whooshbang-v1.d.ts +17 -2
  8. package/fixtures/core-v1/fixture-index.json +1 -1
  9. package/fixtures/core-v1/scenarios/api-credential-invalid-indistinguishable.json +1 -1
  10. package/fixtures/core-v1/scenarios/api-credential-one-time-reveal.json +1 -1
  11. package/fixtures/core-v1/scenarios/api-credential-revocation-replay.json +1 -1
  12. package/fixtures/core-v1/scenarios/api-credential-rotation-overlap.json +1 -1
  13. package/fixtures/core-v1/scenarios/cancellation-too-late.json +1 -1
  14. package/fixtures/core-v1/scenarios/cross-organization-project.json +1 -1
  15. package/fixtures/core-v1/scenarios/cross-project-resource.json +1 -1
  16. package/fixtures/core-v1/scenarios/environment-mismatch.json +1 -1
  17. package/fixtures/core-v1/scenarios/idempotency-conflict.json +1 -1
  18. package/fixtures/core-v1/scenarios/idempotency-equivalent-replay.json +1 -1
  19. package/fixtures/core-v1/scenarios/malformed-bearer.json +1 -1
  20. package/fixtures/core-v1/scenarios/metadata-overrun.json +1 -1
  21. package/fixtures/core-v1/scenarios/missing-scope.json +1 -1
  22. package/fixtures/core-v1/scenarios/project-create-equivalent-replay.json +1 -1
  23. package/fixtures/core-v1/scenarios/project-slug-conflict.json +1 -1
  24. package/fixtures/core-v1/scenarios/provider-outcome-unknown.json +1 -1
  25. package/fixtures/core-v1/scenarios/subscription-activation-replay.json +1 -1
  26. package/fixtures/core-v1/scenarios/subscription-authorization-capability-opacity.json +1 -1
  27. package/fixtures/core-v1/scenarios/subscription-cross-connection-callback-rejected.json +1 -1
  28. package/fixtures/core-v1/scenarios/subscription-expired-replay.json +1 -1
  29. package/fixtures/core-v1/scenarios/subscription-selected-connection-replay.json +1 -1
  30. package/fixtures/interaction-machine-v1/scenarios/ack-conflict.json +1 -1
  31. package/fixtures/interaction-machine-v1/scenarios/ack-cross-machine.json +1 -1
  32. package/fixtures/interaction-machine-v1/scenarios/ack-out-of-order.json +1 -1
  33. package/fixtures/interaction-machine-v1/scenarios/ack-replay.json +1 -1
  34. package/fixtures/interaction-machine-v1/scenarios/ambiguous-free-text.json +1 -1
  35. package/fixtures/interaction-machine-v1/scenarios/callback-token-opacity.json +1 -1
  36. package/fixtures/interaction-machine-v1/scenarios/credential-registration-conflict.json +1 -1
  37. package/fixtures/interaction-machine-v1/scenarios/credential-registration-replay.json +1 -1
  38. package/fixtures/interaction-machine-v1/scenarios/credential-revocation-replay.json +1 -1
  39. package/fixtures/interaction-machine-v1/scenarios/credential-rotation.json +1 -1
  40. package/fixtures/interaction-machine-v1/scenarios/first-credential-activates.json +1 -1
  41. package/fixtures/interaction-machine-v1/scenarios/interaction-duplicate.json +1 -1
  42. package/fixtures/interaction-machine-v1/scenarios/interaction-expired.json +1 -1
  43. package/fixtures/interaction-machine-v1/scenarios/interaction-mismatch.json +1 -1
  44. package/fixtures/interaction-machine-v1/scenarios/interaction-retired.json +1 -1
  45. package/fixtures/interaction-machine-v1/scenarios/interaction-stale.json +1 -1
  46. package/fixtures/interaction-machine-v1/scenarios/machine-admin-denied.json +1 -1
  47. package/fixtures/interaction-machine-v1/scenarios/machine-bound-message-create.json +1 -1
  48. package/fixtures/interaction-machine-v1/scenarios/machine-cancel-denied.json +1 -1
  49. package/fixtures/interaction-machine-v1/scenarios/machine-crash-before-ack.json +1 -1
  50. package/fixtures/interaction-machine-v1/scenarios/machine-notifier-mismatch.json +1 -1
  51. package/fixtures/interaction-machine-v1/scenarios/machine-other-message-read.json +1 -1
  52. package/fixtures/interaction-machine-v1/scenarios/machine-owned-message-read.json +1 -1
  53. package/fixtures/interaction-machine-v1/scenarios/machine-subscriber-mismatch.json +1 -1
  54. package/fixtures/interaction-machine-v1/scenarios/poll-uncommitted-cursor-rejected.json +1 -1
  55. package/fixtures/interaction-machine-v1/scenarios/project-credential-machine-endpoint-denied.json +1 -1
  56. package/fixtures/interaction-machine-v1/scenarios/quarantine-integrity-rejected.json +1 -1
  57. package/fixtures/interaction-machine-v1/scenarios/quarantine-signature-rejected.json +1 -1
  58. package/fixtures/interaction-machine-v1/scenarios/quarantine-valid.json +1 -1
  59. package/fixtures/interaction-machine-v1/scenarios/revoked-machine-credential.json +1 -1
  60. package/fixtures/recipient-experience-v1/scenarios/membership-broadcast-snapshot.json +1 -1
  61. package/fixtures/recipient-experience-v1/scenarios/preferred-binding-resolution.json +1 -1
  62. package/fixtures/recipient-experience-v1/scenarios/recipient-session-security.json +1 -1
  63. package/fixtures/recipient-experience-v1/scenarios/subscriber-initial-groups-transaction.json +1 -1
  64. package/openapi/generated/whooshbang-v1.bundle.json +31 -9
  65. package/openapi/whooshbang-v1.yaml +25 -12
  66. package/package.json +1 -1
  67. package/schemas/core-scenario.schema.json +1 -1
  68. package/schemas/events/agent-binding-degraded-v1.schema.json +1 -1
  69. package/schemas/events/interaction-expired-v1.schema.json +1 -1
  70. package/schemas/events/interaction-received-v1.schema.json +1 -1
  71. package/schemas/events/message-delivered-v1.schema.json +1 -1
  72. package/schemas/events/message-expired-v1.schema.json +1 -1
  73. package/schemas/events/message-failed-v1.schema.json +1 -1
  74. package/schemas/events/message-provider-accepted-v1.schema.json +1 -1
  75. package/schemas/events/subscription-activated-v1.schema.json +1 -1
  76. package/schemas/events/subscription-revoked-v1.schema.json +1 -1
  77. package/schemas/events/whooshbang-event-v1.schema.json +1 -1
  78. package/schemas/fixture-index.schema.json +1 -1
  79. package/schemas/interaction-machine-scenario.schema.json +1 -1
  80. package/schemas/interaction-v1.schema.json +1 -1
  81. package/schemas/machine-v1.schema.json +1 -1
  82. package/schemas/provider-capabilities-v1.schema.json +1 -1
  83. package/schemas/webhooks/webhook-delivery-case-v1.schema.json +1 -1
  84. package/schemas/webhooks/webhook-signing-vector-v1.schema.json +1 -1
  85. package/schemas/whooshbang-v1.schema.json +30 -4
@@ -481,11 +481,11 @@ export type CreateMessageRequest = {
481
481
  to: MessageTarget;
482
482
  notifier_id?: OpaqueIdentifier;
483
483
  /**
484
- * Optional routing override. Simulator delivery and the reserved test: subscriber prefix are test-environment-only; live requests are refused with 400 request_invalid. Omit for notifier-default connection delivery or the reserved test-environment simulator default.
484
+ * Optional routing override. Simulator delivery and the reserved test: subscriber prefix are test-environment-only; live requests are refused with 400 request_invalid. Omit for connection delivery, or for the reserved test-environment simulator default.
485
485
  */
486
486
  delivery_target?: "connection" | "simulator";
487
487
  /**
488
- * Optional fail-closed constraint for a visible connection test. The selected subscriber binding and notifier route must resolve to this exact connection; the service never substitutes another connection or provider.
488
+ * Optional channel connection to send through, from the environment's connections. The subscriber must be connected through it; the service never substitutes another connection or provider. A connection the subscriber has not connected through is refused as `subscriber_not_connected` when they are connected through another, and as an unchosen send would be (`subscriber_unbound` or `preferred_binding_unavailable`) when no connected channel can take the message. Omitted, the service chooses: the subscriber's preferred channel when they set one, otherwise the default connection when they are connected there, otherwise the connection they connected through most recently. The accepted message's `binding.connection_id` records the connection used. Implies `delivery_target: connection`.
489
489
  */
490
490
  connection_id?: OpaqueIdentifier;
491
491
  content: MessageContent;
@@ -6185,6 +6185,21 @@ export interface SubscriberChannelSettings {
6185
6185
  subscriber_id: OpaqueIdentifier;
6186
6186
  channels: RecipientChannelSummary[];
6187
6187
  preference?: PreferredBinding;
6188
+ /**
6189
+ * The connection a message to this subscriber goes through when the sender names none, chosen exactly as a send made now would choose it. Absent when no connected channel can take a message, which a send refuses as `subscriber_unbound`, or when the subscriber's preferred channel cannot, which a send refuses as `preferred_binding_unavailable`.
6190
+ */
6191
+ send_route?: {
6192
+ binding_id: OpaqueIdentifier;
6193
+ /**
6194
+ * An opaque identifier. Its shape, ordering, and embedded content are not public promises.
6195
+ */
6196
+ connection_id?: string;
6197
+ channel: Channel;
6198
+ /**
6199
+ * Why this connection: the subscriber's preferred channel, the default connection, or, when the subscriber is not connected through the default, the connection they connected through most recently.
6200
+ */
6201
+ reason: "preferred" | "default_connection" | "most_recently_connected";
6202
+ };
6188
6203
  diagnostic_id: DiagnosticId;
6189
6204
  }
6190
6205
  /**
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "fixtures": [
4
4
  {
5
5
  "id": "create-project.request",
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "api-credential-invalid-indistinguishable",
4
4
  "category": "credential_lifecycle",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "api-credential-one-time-reveal",
4
4
  "category": "credential_lifecycle",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "api-credential-revocation-replay",
4
4
  "category": "credential_lifecycle",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "api-credential-rotation-overlap",
4
4
  "category": "credential_lifecycle",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "cancellation-too-late",
4
4
  "category": "cancellation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "cross-organization-project",
4
4
  "category": "isolation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "cross-project-resource",
4
4
  "category": "isolation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "environment-mismatch",
4
4
  "category": "isolation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "idempotency-conflict",
4
4
  "category": "idempotency",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "idempotency-equivalent-replay",
4
4
  "category": "idempotency",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "malformed-bearer",
4
4
  "category": "isolation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "metadata-overrun",
4
4
  "category": "message_outcome",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "missing-scope",
4
4
  "category": "isolation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "project-create-equivalent-replay",
4
4
  "category": "idempotency",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "project-slug-conflict",
4
4
  "category": "idempotency",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "provider-outcome-unknown",
4
4
  "category": "message_outcome",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "subscription-activation-replay",
4
4
  "category": "subscription_replay",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "subscription-authorization-capability-opacity",
4
4
  "category": "isolation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "subscription-cross-connection-callback-rejected",
4
4
  "category": "isolation",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "subscription-expired-replay",
4
4
  "category": "subscription_replay",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "subscription-selected-connection-replay",
4
4
  "category": "subscription_replay",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "ack-conflict",
4
4
  "category": "machine_ack",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "ack-cross-machine",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "ack-out-of-order",
4
4
  "category": "machine_ack",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "ack-replay",
4
4
  "category": "machine_ack",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "ambiguous-free-text",
4
4
  "category": "interaction_resolution",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "callback-token-opacity",
4
4
  "category": "callback_token",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "credential-registration-conflict",
4
4
  "category": "machine_credential",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "credential-registration-replay",
4
4
  "category": "machine_credential",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "credential-revocation-replay",
4
4
  "category": "machine_credential",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "credential-rotation",
4
4
  "category": "machine_credential",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "first-credential-activates",
4
4
  "category": "machine_credential",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "interaction-duplicate",
4
4
  "category": "interaction_resolution",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "interaction-expired",
4
4
  "category": "interaction_resolution",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "interaction-mismatch",
4
4
  "category": "interaction_resolution",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "interaction-retired",
4
4
  "category": "interaction_resolution",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "interaction-stale",
4
4
  "category": "interaction_resolution",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-admin-denied",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-bound-message-create",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-cancel-denied",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-crash-before-ack",
4
4
  "category": "machine_poll",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-notifier-mismatch",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-other-message-read",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-owned-message-read",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "machine-subscriber-mismatch",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "poll-uncommitted-cursor-rejected",
4
4
  "category": "machine_poll",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "project-credential-machine-endpoint-denied",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "quarantine-integrity-rejected",
4
4
  "category": "quarantine",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "quarantine-signature-rejected",
4
4
  "category": "quarantine",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "quarantine-valid",
4
4
  "category": "quarantine",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "revoked-machine-credential",
4
4
  "category": "machine_authorization",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "membership-broadcast-snapshot",
4
4
  "category": "membership_broadcast",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "preferred-binding-resolution",
4
4
  "category": "preference_resolution",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "recipient-session-security",
4
4
  "category": "recipient_security",
5
5
  "given": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "contract_version": "2.0.0-rc.4",
2
+ "contract_version": "2.0.0-rc.5",
3
3
  "id": "subscriber-initial-groups-transaction",
4
4
  "category": "subscriber_groups",
5
5
  "given": {
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.1",
3
3
  "info": {
4
4
  "title": "WhooshBang API",
5
- "version": "2.0.0-rc.4",
5
+ "version": "2.0.0-rc.5",
6
6
  "description": "The V1 contract for human organization/project administration, project-scoped\nsubscription links, and asynchronous text messages. A Clerk session selects\none organization for administration. A project credential selects one organization,\nproject, and `test` or `live` environment for product operations; request\nbodies cannot override either authenticated scope.\n\nA person's OAuth grant selects one organization and carries scopes, but no\nproject. It names the project and environment it acts in through the URL\npath, on the environment-scoped form of each operation; the service checks\nthat path against the granting person's membership on every call. The flat\nforms remain credential-only and are unchanged.\n\nResource identifiers are opaque and are not authorization. Reads outside the\ncredential scope return the same `404` shape as absent resources. Provider\ncredentials, raw Telegram identity, and protected provider responses are\nnever part of this API.\n",
7
7
  "termsOfService": "https://flowxo.com/terms",
8
8
  "contact": {
@@ -2014,7 +2014,7 @@
2014
2014
  "post": {
2015
2015
  "operationId": "createMessage",
2016
2016
  "summary": "Create an asynchronous message",
2017
- "description": "Durably accepts one logical text message for one subscriber and one\nresolved channel binding. `202` proves API acceptance only; it does not\nclaim provider acceptance or end-device delivery.\nThe reserved `test:` subscriber prefix and `delivery_target: simulator`\nare test-environment-only. Live sends are refused before acceptance or\nidempotent replay with `400 request_invalid`; reserved subscriber IDs\ncarry a field error at `/to/subscriber_id`.\n",
2017
+ "description": "Durably accepts one logical text message for one subscriber and one\nresolved channel binding. `202` proves API acceptance only; it does not\nclaim provider acceptance or end-device delivery.\nThe reserved `test:` subscriber prefix and `delivery_target: simulator`\nare test-environment-only. Live sends are refused before acceptance or\nidempotent replay with `400 request_invalid`; reserved subscriber IDs\ncarry a field error at `/to/subscriber_id`.\n\n`connection_id` sends through one of the subscriber's connected\nchannels. Without it, the service uses the subscriber's preferred\nchannel, else the default connection when the subscriber is connected\nthere, else the connection they connected through most recently, and\nrefuses with `422 subscriber_unbound` only when no connected channel can\ntake the message. A named connection the subscriber has not connected\nthrough is refused with `422 subscriber_not_connected` when they are\nconnected through another one, and as an unchosen send would be when\nnone can take the message. A named connection that is not in this\nenvironment, or cannot send, is refused with `400 request_invalid` at\n`/connection_id`.\n",
2018
2018
  "tags": ["Messages"],
2019
2019
  "security": [{ "bearerCredential": [] }, { "machineCredential": [] }],
2020
2020
  "x-required-scopes": ["messages:write"],
@@ -5025,7 +5025,7 @@
5025
5025
  "get": {
5026
5026
  "operationId": "listNotifierConnections",
5027
5027
  "summary": "Read which connection each notifier sends through",
5028
- "description": "Every route in this environment, ordered by notifier and then\nconnection.\n\nA connection nothing routes to is configured and inert: it delivers\nnothing and a subscriber cannot authorize against it either. This list\nis therefore the answer to \"my connection is active, so why is nothing\narriving?\" — an environment with connections and no default route is\nthe ordinary shape of that question.\n",
5028
+ "description": "Every route in this environment, ordered by notifier and then\nconnection.\n\nThe default route decides which connection a message goes through\nwhen the subscriber is connected there and the sender names none. A\nsubscriber who is not connected through the default is reached through\nthe connection they connected through most recently, and a sender may\nname any connection the subscriber connected through. Routes never\nstop a connection sending; pausing the connection does.\n",
5029
5029
  "tags": ["Channel connections"],
5030
5030
  "security": [
5031
5031
  { "clerkSession": [] },
@@ -5166,7 +5166,7 @@
5166
5166
  "delete": {
5167
5167
  "operationId": "detachNotifierConnection",
5168
5168
  "summary": "Stop routing a notifier through a connection",
5169
- "description": "Removes one route. The connection itself is untouched and keeps its\nidentity, its credential custody, and every binding subscribers gave\nit — this is the reversible half of retiring an identity, and archive\nis the terminal one.\n\nDetaching the default leaves the notifier with no default, which stops\nits sends and new authorizations rather than moving them somewhere\nelse. That refusal is the point: a notifier silently failing over to\nanother identity would put a different bot in front of subscribers who\nnever consented to it.\n\nRepeat-safe. Removing a route that is already gone returns the\nnotifier's remaining routes rather than a 404, because a caller that\nlost the first response must be able to confirm the outcome.\n",
5169
+ "description": "Removes one route. The connection itself is untouched and keeps its\nidentity, its credential custody, and every binding subscribers gave\nit — this is the reversible half of retiring an identity, and archive\nis the terminal one.\n\nDetaching the default leaves the notifier with no default, and each\nmessage then goes through the connection its subscriber connected\nthrough most recently. No message ever reaches a subscriber through an\nidentity they did not connect through. To stop a connection sending,\npause it.\n\nRepeat-safe. Removing a route that is already gone returns the\nnotifier's remaining routes rather than a 404, because a caller that\nlost the first response must be able to confirm the outcome.\n",
5170
5170
  "tags": ["Channel connections"],
5171
5171
  "security": [
5172
5172
  { "clerkSession": [] },
@@ -12892,11 +12892,11 @@
12892
12892
  },
12893
12893
  "delivery_target": {
12894
12894
  "$ref": "#/components/schemas/MessageDeliveryTarget",
12895
- "description": "Optional routing override. Simulator delivery and the reserved test: subscriber prefix are test-environment-only; live requests are refused with 400 request_invalid. Omit for notifier-default connection delivery or the reserved test-environment simulator default."
12895
+ "description": "Optional routing override. Simulator delivery and the reserved test: subscriber prefix are test-environment-only; live requests are refused with 400 request_invalid. Omit for connection delivery, or for the reserved test-environment simulator default."
12896
12896
  },
12897
12897
  "connection_id": {
12898
12898
  "allOf": [{ "$ref": "#/components/schemas/OpaqueIdentifier" }],
12899
- "description": "Optional fail-closed constraint for a visible connection test. The selected subscriber binding and notifier route must resolve to this exact connection; the service never substitutes another connection or provider."
12899
+ "description": "Optional channel connection to send through, from the environment's connections. The subscriber must be connected through it; the service never substitutes another connection or provider. A connection the subscriber has not connected through is refused as `subscriber_not_connected` when they are connected through another, and as an unchosen send would be (`subscriber_unbound` or `preferred_binding_unavailable`) when no connected channel can take the message. Omitted, the service chooses: the subscriber's preferred channel when they set one, otherwise the default connection when they are connected there, otherwise the connection they connected through most recently. The accepted message's `binding.connection_id` records the connection used. Implies `delivery_target: connection`."
12900
12900
  },
12901
12901
  "content": { "$ref": "#/components/schemas/MessageContent" },
12902
12902
  "expires_at": {
@@ -12918,7 +12918,6 @@
12918
12918
  "properties": { "connection_id": true }
12919
12919
  },
12920
12920
  "then": {
12921
- "required": ["delivery_target"],
12922
12921
  "properties": { "delivery_target": { "const": "connection" } }
12923
12922
  }
12924
12923
  }
@@ -14678,6 +14677,29 @@
14678
14677
  "items": { "$ref": "#/components/schemas/RecipientChannelSummary" }
14679
14678
  },
14680
14679
  "preference": { "$ref": "#/components/schemas/PreferredBinding" },
14680
+ "send_route": {
14681
+ "type": "object",
14682
+ "description": "The connection a message to this subscriber goes through when the sender names none, chosen exactly as a send made now would choose it. Absent when no connected channel can take a message, which a send refuses as `subscriber_unbound`, or when the subscriber's preferred channel cannot, which a send refuses as `preferred_binding_unavailable`.",
14683
+ "required": ["binding_id", "channel", "reason"],
14684
+ "properties": {
14685
+ "binding_id": { "$ref": "#/components/schemas/OpaqueIdentifier" },
14686
+ "connection_id": {
14687
+ "$ref": "#/components/schemas/OpaqueIdentifier",
14688
+ "description": "Absent only on a legacy binding that predates channel connections."
14689
+ },
14690
+ "channel": { "$ref": "#/components/schemas/Channel" },
14691
+ "reason": {
14692
+ "type": "string",
14693
+ "enum": [
14694
+ "preferred",
14695
+ "default_connection",
14696
+ "most_recently_connected"
14697
+ ],
14698
+ "description": "Why this connection: the subscriber's preferred channel, the default connection, or, when the subscriber is not connected through the default, the connection they connected through most recently."
14699
+ }
14700
+ },
14701
+ "additionalProperties": false
14702
+ },
14681
14703
  "diagnostic_id": { "$ref": "#/components/schemas/DiagnosticId" }
14682
14704
  },
14683
14705
  "additionalProperties": false
@@ -17620,7 +17642,7 @@
17620
17642
  "provider-capabilities-v1.schema": {
17621
17643
  "$schema": "https://json-schema.org/draft/2020-12/schema",
17622
17644
  "$id": "https://whooshbang.flowxo.com/schemas/provider-capabilities-v1.schema.json",
17623
- "x-contract-version": "2.0.0-rc.4",
17645
+ "x-contract-version": "2.0.0-rc.5",
17624
17646
  "title": "ProviderCapabilitiesV1",
17625
17647
  "description": "Provider-neutral, renderer-facing delivery and interaction capabilities with explicit degradation.",
17626
17648
  "type": "object",
@@ -18340,5 +18362,5 @@
18340
18362
  }
18341
18363
  }
18342
18364
  },
18343
- "x-contract-version": "2.0.0-rc.4"
18365
+ "x-contract-version": "2.0.0-rc.5"
18344
18366
  }