@contractspec/example.locale-jurisdiction-gate 3.7.6 → 3.7.10

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 (83) hide show
  1. package/.turbo/turbo-build.log +72 -51
  2. package/AGENTS.md +50 -27
  3. package/CHANGELOG.md +21 -0
  4. package/README.md +87 -42
  5. package/dist/browser/entities/index.js +2 -2
  6. package/dist/browser/entities/models.js +2 -2
  7. package/dist/browser/events.js +1 -1
  8. package/dist/browser/forms/assistant-context.form.js +213 -0
  9. package/dist/browser/forms/index.js +213 -0
  10. package/dist/browser/index.js +362 -40
  11. package/dist/browser/locale-jurisdiction-gate.feature.js +66 -1
  12. package/dist/browser/operations/assistant.js +3 -3
  13. package/dist/browser/operations/index.js +3 -3
  14. package/dist/browser/policy/assistant-gate.policy.js +62 -0
  15. package/dist/browser/policy/index.js +62 -1
  16. package/dist/browser/translations/assistant-gate.en-GB.translation.js +48 -0
  17. package/dist/browser/translations/assistant-gate.en-US.translation.js +50 -0
  18. package/dist/browser/translations/assistant-gate.fr-FR.translation.js +52 -0
  19. package/dist/browser/translations/index.js +148 -0
  20. package/dist/contracts.test.d.ts +1 -0
  21. package/dist/entities/index.js +2 -2
  22. package/dist/entities/models.js +2 -2
  23. package/dist/events.js +1 -1
  24. package/dist/forms/assistant-context.form.d.ts +22 -0
  25. package/dist/forms/assistant-context.form.js +214 -0
  26. package/dist/forms/index.d.ts +1 -0
  27. package/dist/forms/index.js +214 -0
  28. package/dist/index.d.ts +5 -3
  29. package/dist/index.js +362 -40
  30. package/dist/locale-jurisdiction-gate.feature.js +66 -1
  31. package/dist/node/entities/index.js +2 -2
  32. package/dist/node/entities/models.js +2 -2
  33. package/dist/node/events.js +1 -1
  34. package/dist/node/forms/assistant-context.form.js +213 -0
  35. package/dist/node/forms/index.js +213 -0
  36. package/dist/node/index.js +362 -40
  37. package/dist/node/locale-jurisdiction-gate.feature.js +66 -1
  38. package/dist/node/operations/assistant.js +3 -3
  39. package/dist/node/operations/index.js +3 -3
  40. package/dist/node/policy/assistant-gate.policy.js +62 -0
  41. package/dist/node/policy/index.js +62 -1
  42. package/dist/node/translations/assistant-gate.en-GB.translation.js +48 -0
  43. package/dist/node/translations/assistant-gate.en-US.translation.js +50 -0
  44. package/dist/node/translations/assistant-gate.fr-FR.translation.js +52 -0
  45. package/dist/node/translations/index.js +148 -0
  46. package/dist/operations/assistant.js +3 -3
  47. package/dist/operations/index.js +3 -3
  48. package/dist/policy/assistant-gate.policy.d.ts +1 -0
  49. package/dist/policy/assistant-gate.policy.js +63 -0
  50. package/dist/policy/index.d.ts +2 -1
  51. package/dist/policy/index.js +62 -1
  52. package/dist/translations/assistant-gate.en-GB.translation.d.ts +1 -0
  53. package/dist/translations/assistant-gate.en-GB.translation.js +49 -0
  54. package/dist/translations/assistant-gate.en-US.translation.d.ts +1 -0
  55. package/dist/translations/assistant-gate.en-US.translation.js +51 -0
  56. package/dist/translations/assistant-gate.fr-FR.translation.d.ts +1 -0
  57. package/dist/translations/assistant-gate.fr-FR.translation.js +53 -0
  58. package/dist/translations/index.d.ts +3 -0
  59. package/dist/translations/index.js +149 -0
  60. package/package.json +105 -7
  61. package/src/contracts.test.ts +32 -0
  62. package/src/docs/locale-jurisdiction-gate.docblock.ts +21 -21
  63. package/src/entities/models.ts +87 -87
  64. package/src/events.ts +55 -55
  65. package/src/example.ts +28 -28
  66. package/src/forms/assistant-context.form.ts +112 -0
  67. package/src/forms/index.ts +1 -0
  68. package/src/handlers/demo.handlers.test.ts +46 -46
  69. package/src/handlers/demo.handlers.ts +133 -133
  70. package/src/index.ts +5 -3
  71. package/src/locale-jurisdiction-gate.feature.ts +40 -34
  72. package/src/operations/assistant.ts +82 -82
  73. package/src/policy/assistant-gate.policy.ts +65 -0
  74. package/src/policy/guard.test.ts +18 -18
  75. package/src/policy/guard.ts +75 -75
  76. package/src/policy/index.ts +2 -1
  77. package/src/policy/types.ts +12 -12
  78. package/src/translations/assistant-gate.en-GB.translation.ts +46 -0
  79. package/src/translations/assistant-gate.en-US.translation.ts +48 -0
  80. package/src/translations/assistant-gate.fr-FR.translation.ts +51 -0
  81. package/src/translations/index.ts +3 -0
  82. package/tsconfig.json +7 -15
  83. package/tsdown.config.js +7 -13
package/dist/index.js CHANGED
@@ -44,9 +44,9 @@ var docBlocks = [
44
44
  registerDocBlocks(docBlocks);
45
45
  // src/entities/models.ts
46
46
  import {
47
- ScalarTypeEnum,
48
47
  defineEnum,
49
- defineSchemaModel
48
+ defineSchemaModel,
49
+ ScalarTypeEnum
50
50
  } from "@contractspec/lib.schema";
51
51
  var AllowedScopeEnum = defineEnum("AllowedScope", [
52
52
  "education_only",
@@ -145,7 +145,7 @@ var AssistantAnswerIRModel = defineSchemaModel({
145
145
  });
146
146
  // src/events.ts
147
147
  import { defineEvent } from "@contractspec/lib.contracts-spec";
148
- import { ScalarTypeEnum as ScalarTypeEnum2, defineSchemaModel as defineSchemaModel2 } from "@contractspec/lib.schema";
148
+ import { defineSchemaModel as defineSchemaModel2, ScalarTypeEnum as ScalarTypeEnum2 } from "@contractspec/lib.schema";
149
149
  var AssistantAnswerRequestedPayload = defineSchemaModel2({
150
150
  name: "AssistantAnswerRequestedPayload",
151
151
  description: "Emitted when an assistant answer is requested (pre-gate).",
@@ -245,6 +245,114 @@ var example = defineExample({
245
245
  });
246
246
  var example_default = example;
247
247
 
248
+ // src/forms/assistant-context.form.ts
249
+ import { defineFormSpec } from "@contractspec/lib.contracts-spec/forms";
250
+ import {
251
+ OwnersEnum,
252
+ StabilityEnum,
253
+ TagsEnum
254
+ } from "@contractspec/lib.contracts-spec/ownership";
255
+ import { defineSchemaModel as defineSchemaModel3, ScalarTypeEnum as ScalarTypeEnum3 } from "@contractspec/lib.schema";
256
+ var AssistantContextFormModel = defineSchemaModel3({
257
+ name: "AssistantContextFormModel",
258
+ description: "Form values required before a policy-gated assistant request can be executed.",
259
+ fields: {
260
+ locale: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
261
+ jurisdiction: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
262
+ kbSnapshotId: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false },
263
+ allowedScope: { type: AllowedScopeEnum, isOptional: false },
264
+ question: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
265
+ }
266
+ });
267
+ var AssistantContextForm = defineFormSpec({
268
+ meta: {
269
+ key: "locale-jurisdiction-gate.form.assistant-context",
270
+ version: "1.0.0",
271
+ title: "Assistant Context Gate",
272
+ description: "Collects the explicit locale, jurisdiction, scope, and knowledge snapshot required by the assistant gate.",
273
+ domain: "assistant",
274
+ owners: [OwnersEnum.PlatformFinance],
275
+ tags: [TagsEnum.I18n, "assistant", "form", "policy"],
276
+ stability: StabilityEnum.Experimental
277
+ },
278
+ model: AssistantContextFormModel,
279
+ fields: [
280
+ {
281
+ kind: "select",
282
+ name: "locale",
283
+ labelI18n: "assistantGate.locale.label",
284
+ descriptionI18n: "assistantGate.locale.description",
285
+ options: {
286
+ kind: "static",
287
+ options: [
288
+ { labelI18n: "assistantGate.locale.enUs", value: "en-US" },
289
+ { labelI18n: "assistantGate.locale.enGb", value: "en-GB" },
290
+ { labelI18n: "assistantGate.locale.frFr", value: "fr-FR" }
291
+ ]
292
+ },
293
+ required: true
294
+ },
295
+ {
296
+ kind: "text",
297
+ name: "jurisdiction",
298
+ labelI18n: "assistantGate.jurisdiction.label",
299
+ placeholderI18n: "assistantGate.jurisdiction.placeholder",
300
+ required: true
301
+ },
302
+ {
303
+ kind: "text",
304
+ name: "kbSnapshotId",
305
+ labelI18n: "assistantGate.kbSnapshotId.label",
306
+ placeholderI18n: "assistantGate.kbSnapshotId.placeholder",
307
+ required: true
308
+ },
309
+ {
310
+ kind: "radio",
311
+ name: "allowedScope",
312
+ labelI18n: "assistantGate.allowedScope.label",
313
+ options: {
314
+ kind: "static",
315
+ options: [
316
+ {
317
+ labelI18n: "assistantGate.allowedScope.educationOnly",
318
+ value: "education_only"
319
+ },
320
+ {
321
+ labelI18n: "assistantGate.allowedScope.genericInfo",
322
+ value: "generic_info"
323
+ },
324
+ {
325
+ labelI18n: "assistantGate.allowedScope.escalationRequired",
326
+ value: "escalation_required"
327
+ }
328
+ ]
329
+ },
330
+ required: true
331
+ },
332
+ {
333
+ kind: "textarea",
334
+ name: "question",
335
+ labelI18n: "assistantGate.question.label",
336
+ placeholderI18n: "assistantGate.question.placeholder",
337
+ required: true
338
+ }
339
+ ],
340
+ actions: [
341
+ {
342
+ key: "submit",
343
+ labelI18n: "assistantGate.submit.label",
344
+ op: { name: "assistant.answer", version: "1.0.0" }
345
+ }
346
+ ],
347
+ policy: {
348
+ flags: [],
349
+ pii: ["kbSnapshotId", "question"]
350
+ },
351
+ renderHints: {
352
+ ui: "custom",
353
+ form: "react-hook-form"
354
+ }
355
+ });
248
356
  // src/policy/guard.ts
249
357
  var SUPPORTED_LOCALES = new Set(["en-US", "en-GB", "fr-FR"]);
250
358
  function err(code, message) {
@@ -394,23 +502,126 @@ function createDemoAssistantHandlers() {
394
502
  }
395
503
  return { answer, explainConcept };
396
504
  }
505
+ // src/policy/assistant-gate.policy.ts
506
+ import {
507
+ OwnersEnum as OwnersEnum2,
508
+ StabilityEnum as StabilityEnum2,
509
+ TagsEnum as TagsEnum2
510
+ } from "@contractspec/lib.contracts-spec/ownership";
511
+ import { definePolicy } from "@contractspec/lib.contracts-spec/policy";
512
+ var AssistantGatePolicy = definePolicy({
513
+ meta: {
514
+ key: "locale-jurisdiction-gate.policy.gate",
515
+ version: "1.0.0",
516
+ title: "Assistant Locale and Jurisdiction Gate",
517
+ description: "Requires explicit locale, jurisdiction, knowledge snapshot, and allowed scope before assistant requests may proceed.",
518
+ domain: "assistant",
519
+ scope: "operation",
520
+ owners: [OwnersEnum2.PlatformFinance],
521
+ tags: [TagsEnum2.I18n, "assistant", "policy", "jurisdiction"],
522
+ stability: StabilityEnum2.Experimental
523
+ },
524
+ rules: [
525
+ {
526
+ effect: "deny",
527
+ actions: ["assistant.answer", "assistant.explainConcept"],
528
+ resource: { type: "assistant-call" },
529
+ conditions: [
530
+ {
531
+ expression: "!context.locale || !context.jurisdiction || !context.kbSnapshotId || !context.allowedScope"
532
+ }
533
+ ],
534
+ reason: "Assistant requests fail closed until locale, jurisdiction, kbSnapshotId, and allowedScope are explicit."
535
+ },
536
+ {
537
+ effect: "deny",
538
+ actions: ["assistant.answer", "assistant.explainConcept"],
539
+ resource: { type: "assistant-call" },
540
+ conditions: [
541
+ {
542
+ expression: "!['en-US', 'en-GB', 'fr-FR'].includes(context.locale ?? '')"
543
+ }
544
+ ],
545
+ reason: "Only the explicitly reviewed assistant locales are permitted."
546
+ },
547
+ {
548
+ effect: "allow",
549
+ actions: ["assistant.answer", "assistant.explainConcept"],
550
+ resource: { type: "assistant-call" },
551
+ conditions: [
552
+ {
553
+ expression: "['en-US', 'en-GB', 'fr-FR'].includes(context.locale ?? '') && !!context.jurisdiction && !!context.kbSnapshotId && !!context.allowedScope"
554
+ }
555
+ ],
556
+ reason: "Explicit context is present, so the request may continue to citation and scope validation."
557
+ }
558
+ ],
559
+ pii: {
560
+ fields: ["kbSnapshotId"],
561
+ retentionDays: 30
562
+ }
563
+ });
564
+
565
+ // src/locale-jurisdiction-gate.feature.ts
566
+ import { defineFeature } from "@contractspec/lib.contracts-spec";
567
+ var LocaleJurisdictionGateFeature = defineFeature({
568
+ meta: {
569
+ key: "locale-jurisdiction-gate",
570
+ version: "1.0.0",
571
+ title: "Locale + Jurisdiction Gate",
572
+ description: "Fail-closed gating for assistant calls requiring locale/jurisdiction/snapshot/scope and citations.",
573
+ domain: "knowledge",
574
+ owners: ["@examples"],
575
+ tags: ["assistant", "policy", "locale", "jurisdiction", "knowledge"],
576
+ stability: "experimental"
577
+ },
578
+ operations: [
579
+ { key: "assistant.answer", version: "1.0.0" },
580
+ { key: "assistant.explainConcept", version: "1.0.0" }
581
+ ],
582
+ events: [
583
+ { key: "assistant.answer.requested", version: "1.0.0" },
584
+ { key: "assistant.answer.blocked", version: "1.0.0" },
585
+ { key: "assistant.answer.delivered", version: "1.0.0" }
586
+ ],
587
+ presentations: [],
588
+ opToPresentation: [],
589
+ presentationsTargets: [],
590
+ capabilities: {
591
+ requires: [{ key: "knowledge", version: "1.0.0" }]
592
+ },
593
+ policies: [
594
+ {
595
+ key: AssistantGatePolicy.meta.key,
596
+ version: AssistantGatePolicy.meta.version
597
+ }
598
+ ],
599
+ knowledge: [
600
+ { key: "locale-jurisdiction-gate.knowledge.rules", version: "1.0.0" }
601
+ ],
602
+ docs: [
603
+ "docs.examples.locale-jurisdiction-gate.goal",
604
+ "docs.examples.locale-jurisdiction-gate.reference"
605
+ ]
606
+ });
607
+
397
608
  // src/operations/assistant.ts
398
609
  import { defineCommand } from "@contractspec/lib.contracts-spec";
399
- import { ScalarTypeEnum as ScalarTypeEnum3, defineSchemaModel as defineSchemaModel3 } from "@contractspec/lib.schema";
400
- var AssistantQuestionInput = defineSchemaModel3({
610
+ import { defineSchemaModel as defineSchemaModel4, ScalarTypeEnum as ScalarTypeEnum4 } from "@contractspec/lib.schema";
611
+ var AssistantQuestionInput = defineSchemaModel4({
401
612
  name: "AssistantQuestionInput",
402
613
  description: "Input for assistant calls with mandatory envelope.",
403
614
  fields: {
404
615
  envelope: { type: LLMCallEnvelopeModel, isOptional: false },
405
- question: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
616
+ question: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false }
406
617
  }
407
618
  });
408
- var AssistantConceptInput = defineSchemaModel3({
619
+ var AssistantConceptInput = defineSchemaModel4({
409
620
  name: "AssistantConceptInput",
410
621
  description: "Input for explaining a concept with mandatory envelope.",
411
622
  fields: {
412
623
  envelope: { type: LLMCallEnvelopeModel, isOptional: false },
413
- conceptKey: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
624
+ conceptKey: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false }
414
625
  }
415
626
  });
416
627
  var AssistantAnswerContract = defineCommand({
@@ -480,42 +691,148 @@ var AssistantExplainConceptContract = defineCommand({
480
691
  },
481
692
  policy: { auth: "user" }
482
693
  });
483
- // src/locale-jurisdiction-gate.feature.ts
484
- import { defineFeature } from "@contractspec/lib.contracts-spec";
485
- var LocaleJurisdictionGateFeature = defineFeature({
694
+ // src/translations/assistant-gate.en-GB.translation.ts
695
+ import {
696
+ OwnersEnum as OwnersEnum3,
697
+ StabilityEnum as StabilityEnum3,
698
+ TagsEnum as TagsEnum3
699
+ } from "@contractspec/lib.contracts-spec/ownership";
700
+ import { defineTranslation } from "@contractspec/lib.contracts-spec/translations/spec";
701
+ var AssistantGateMessagesEnGb = defineTranslation({
486
702
  meta: {
487
- key: "locale-jurisdiction-gate",
703
+ key: "locale-jurisdiction-gate.translation.assistant-gate.en-GB",
488
704
  version: "1.0.0",
489
- title: "Locale + Jurisdiction Gate",
490
- description: "Fail-closed gating for assistant calls requiring locale/jurisdiction/snapshot/scope and citations.",
491
- domain: "knowledge",
492
- owners: ["@examples"],
493
- tags: ["assistant", "policy", "locale", "jurisdiction", "knowledge"],
494
- stability: "experimental"
705
+ domain: "assistant",
706
+ description: "British English messages for the assistant locale and jurisdiction gate.",
707
+ owners: [OwnersEnum3.PlatformFinance],
708
+ stability: StabilityEnum3.Experimental,
709
+ tags: [TagsEnum3.I18n, "assistant", "policy"]
495
710
  },
496
- operations: [
497
- { key: "assistant.answer", version: "1.0.0" },
498
- { key: "assistant.explainConcept", version: "1.0.0" }
499
- ],
500
- events: [
501
- { key: "assistant.answer.requested", version: "1.0.0" },
502
- { key: "assistant.answer.blocked", version: "1.0.0" },
503
- { key: "assistant.answer.delivered", version: "1.0.0" }
504
- ],
505
- presentations: [],
506
- opToPresentation: [],
507
- presentationsTargets: [],
508
- capabilities: {
509
- requires: [{ key: "knowledge", version: "1.0.0" }]
711
+ locale: "en-GB",
712
+ fallback: "en-US",
713
+ messages: {
714
+ "assistantGate.locale.label": { value: "Locale" },
715
+ "assistantGate.locale.description": {
716
+ value: "Select the reviewed locale for the assistant response."
717
+ },
718
+ "assistantGate.jurisdiction.label": { value: "Jurisdiction" },
719
+ "assistantGate.jurisdiction.placeholder": { value: "UK-FCA" },
720
+ "assistantGate.kbSnapshotId.label": { value: "Knowledge snapshot ID" },
721
+ "assistantGate.kbSnapshotId.placeholder": {
722
+ value: "kb_2026_03_20_policy_reviewed"
723
+ },
724
+ "assistantGate.allowedScope.label": { value: "Permitted scope" },
725
+ "assistantGate.allowedScope.educationOnly": {
726
+ value: "Educational content only"
727
+ },
728
+ "assistantGate.allowedScope.genericInfo": { value: "General information" },
729
+ "assistantGate.allowedScope.escalationRequired": {
730
+ value: "Escalation required"
731
+ },
732
+ "assistantGate.question.label": { value: "Question" },
733
+ "assistantGate.question.placeholder": {
734
+ value: "What may I say about this product in the selected jurisdiction?"
735
+ },
736
+ "assistantGate.submit.label": { value: "Generate response" }
737
+ }
738
+ });
739
+
740
+ // src/translations/assistant-gate.en-US.translation.ts
741
+ import {
742
+ OwnersEnum as OwnersEnum4,
743
+ StabilityEnum as StabilityEnum4,
744
+ TagsEnum as TagsEnum4
745
+ } from "@contractspec/lib.contracts-spec/ownership";
746
+ import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations/spec";
747
+ var AssistantGateMessagesEnUs = defineTranslation2({
748
+ meta: {
749
+ key: "locale-jurisdiction-gate.translation.assistant-gate.en-US",
750
+ version: "1.0.0",
751
+ domain: "assistant",
752
+ description: "US English messages for the assistant locale and jurisdiction gate.",
753
+ owners: [OwnersEnum4.PlatformFinance],
754
+ stability: StabilityEnum4.Experimental,
755
+ tags: [TagsEnum4.I18n, "assistant", "policy"]
510
756
  },
511
- policies: [{ key: "locale-jurisdiction-gate.policy.gate", version: "1.0.0" }],
512
- knowledge: [
513
- { key: "locale-jurisdiction-gate.knowledge.rules", version: "1.0.0" }
514
- ],
515
- docs: [
516
- "docs.examples.locale-jurisdiction-gate.goal",
517
- "docs.examples.locale-jurisdiction-gate.reference"
518
- ]
757
+ locale: "en-US",
758
+ messages: {
759
+ "assistantGate.locale.label": { value: "Locale" },
760
+ "assistantGate.locale.description": {
761
+ value: "Choose the reviewed locale for the assistant answer."
762
+ },
763
+ "assistantGate.locale.enUs": { value: "English (United States)" },
764
+ "assistantGate.locale.enGb": { value: "English (United Kingdom)" },
765
+ "assistantGate.locale.frFr": { value: "French (France)" },
766
+ "assistantGate.jurisdiction.label": { value: "Jurisdiction" },
767
+ "assistantGate.jurisdiction.placeholder": { value: "US-SEC" },
768
+ "assistantGate.kbSnapshotId.label": { value: "Knowledge snapshot ID" },
769
+ "assistantGate.kbSnapshotId.placeholder": {
770
+ value: "kb_2026_03_20_policy_reviewed"
771
+ },
772
+ "assistantGate.allowedScope.label": { value: "Allowed scope" },
773
+ "assistantGate.allowedScope.educationOnly": {
774
+ value: "Educational content only"
775
+ },
776
+ "assistantGate.allowedScope.genericInfo": { value: "Generic information" },
777
+ "assistantGate.allowedScope.escalationRequired": {
778
+ value: "Escalation required"
779
+ },
780
+ "assistantGate.question.label": { value: "Question" },
781
+ "assistantGate.question.placeholder": {
782
+ value: "What can I say about this product in the selected jurisdiction?"
783
+ },
784
+ "assistantGate.submit.label": { value: "Generate answer" }
785
+ }
786
+ });
787
+
788
+ // src/translations/assistant-gate.fr-FR.translation.ts
789
+ import {
790
+ OwnersEnum as OwnersEnum5,
791
+ StabilityEnum as StabilityEnum5,
792
+ TagsEnum as TagsEnum5
793
+ } from "@contractspec/lib.contracts-spec/ownership";
794
+ import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations/spec";
795
+ var AssistantGateMessagesFrFr = defineTranslation3({
796
+ meta: {
797
+ key: "locale-jurisdiction-gate.translation.assistant-gate.fr-FR",
798
+ version: "1.0.0",
799
+ domain: "assistant",
800
+ description: "French messages for the assistant locale and jurisdiction gate.",
801
+ owners: [OwnersEnum5.PlatformFinance],
802
+ stability: StabilityEnum5.Experimental,
803
+ tags: [TagsEnum5.I18n, "assistant", "policy"]
804
+ },
805
+ locale: "fr-FR",
806
+ fallback: "en-US",
807
+ messages: {
808
+ "assistantGate.locale.label": { value: "Langue" },
809
+ "assistantGate.locale.description": {
810
+ value: "S\xE9lectionnez la langue valid\xE9e pour la r\xE9ponse de l'assistant."
811
+ },
812
+ "assistantGate.jurisdiction.label": { value: "Juridiction" },
813
+ "assistantGate.jurisdiction.placeholder": { value: "FR-AMF" },
814
+ "assistantGate.kbSnapshotId.label": {
815
+ value: "Identifiant du snapshot documentaire"
816
+ },
817
+ "assistantGate.kbSnapshotId.placeholder": {
818
+ value: "kb_2026_03_20_policy_reviewed"
819
+ },
820
+ "assistantGate.allowedScope.label": { value: "P\xE9rim\xE8tre autoris\xE9" },
821
+ "assistantGate.allowedScope.educationOnly": {
822
+ value: "Contenu \xE9ducatif uniquement"
823
+ },
824
+ "assistantGate.allowedScope.genericInfo": {
825
+ value: "Information g\xE9n\xE9rale"
826
+ },
827
+ "assistantGate.allowedScope.escalationRequired": {
828
+ value: "Escalade obligatoire"
829
+ },
830
+ "assistantGate.question.label": { value: "Question" },
831
+ "assistantGate.question.placeholder": {
832
+ value: "Que puis-je dire sur ce produit dans la juridiction s\xE9lectionn\xE9e ?"
833
+ },
834
+ "assistantGate.submit.label": { value: "G\xE9n\xE9rer la r\xE9ponse" }
835
+ }
519
836
  });
520
837
  export {
521
838
  validateEnvelope,
@@ -527,7 +844,12 @@ export {
527
844
  RegulatoryContextModel,
528
845
  LocaleJurisdictionGateFeature,
529
846
  LLMCallEnvelopeModel,
847
+ AssistantGatePolicy,
848
+ AssistantGateMessagesFrFr,
849
+ AssistantGateMessagesEnUs,
850
+ AssistantGateMessagesEnGb,
530
851
  AssistantExplainConceptContract,
852
+ AssistantContextForm,
531
853
  AssistantCitationModel,
532
854
  AssistantAnswerSectionModel,
533
855
  AssistantAnswerRequestedEvent,
@@ -1,4 +1,64 @@
1
1
  // @bun
2
+ // src/policy/assistant-gate.policy.ts
3
+ import {
4
+ OwnersEnum,
5
+ StabilityEnum,
6
+ TagsEnum
7
+ } from "@contractspec/lib.contracts-spec/ownership";
8
+ import { definePolicy } from "@contractspec/lib.contracts-spec/policy";
9
+ var AssistantGatePolicy = definePolicy({
10
+ meta: {
11
+ key: "locale-jurisdiction-gate.policy.gate",
12
+ version: "1.0.0",
13
+ title: "Assistant Locale and Jurisdiction Gate",
14
+ description: "Requires explicit locale, jurisdiction, knowledge snapshot, and allowed scope before assistant requests may proceed.",
15
+ domain: "assistant",
16
+ scope: "operation",
17
+ owners: [OwnersEnum.PlatformFinance],
18
+ tags: [TagsEnum.I18n, "assistant", "policy", "jurisdiction"],
19
+ stability: StabilityEnum.Experimental
20
+ },
21
+ rules: [
22
+ {
23
+ effect: "deny",
24
+ actions: ["assistant.answer", "assistant.explainConcept"],
25
+ resource: { type: "assistant-call" },
26
+ conditions: [
27
+ {
28
+ expression: "!context.locale || !context.jurisdiction || !context.kbSnapshotId || !context.allowedScope"
29
+ }
30
+ ],
31
+ reason: "Assistant requests fail closed until locale, jurisdiction, kbSnapshotId, and allowedScope are explicit."
32
+ },
33
+ {
34
+ effect: "deny",
35
+ actions: ["assistant.answer", "assistant.explainConcept"],
36
+ resource: { type: "assistant-call" },
37
+ conditions: [
38
+ {
39
+ expression: "!['en-US', 'en-GB', 'fr-FR'].includes(context.locale ?? '')"
40
+ }
41
+ ],
42
+ reason: "Only the explicitly reviewed assistant locales are permitted."
43
+ },
44
+ {
45
+ effect: "allow",
46
+ actions: ["assistant.answer", "assistant.explainConcept"],
47
+ resource: { type: "assistant-call" },
48
+ conditions: [
49
+ {
50
+ expression: "['en-US', 'en-GB', 'fr-FR'].includes(context.locale ?? '') && !!context.jurisdiction && !!context.kbSnapshotId && !!context.allowedScope"
51
+ }
52
+ ],
53
+ reason: "Explicit context is present, so the request may continue to citation and scope validation."
54
+ }
55
+ ],
56
+ pii: {
57
+ fields: ["kbSnapshotId"],
58
+ retentionDays: 30
59
+ }
60
+ });
61
+
2
62
  // src/locale-jurisdiction-gate.feature.ts
3
63
  import { defineFeature } from "@contractspec/lib.contracts-spec";
4
64
  var LocaleJurisdictionGateFeature = defineFeature({
@@ -27,7 +87,12 @@ var LocaleJurisdictionGateFeature = defineFeature({
27
87
  capabilities: {
28
88
  requires: [{ key: "knowledge", version: "1.0.0" }]
29
89
  },
30
- policies: [{ key: "locale-jurisdiction-gate.policy.gate", version: "1.0.0" }],
90
+ policies: [
91
+ {
92
+ key: AssistantGatePolicy.meta.key,
93
+ version: AssistantGatePolicy.meta.version
94
+ }
95
+ ],
31
96
  knowledge: [
32
97
  { key: "locale-jurisdiction-gate.knowledge.rules", version: "1.0.0" }
33
98
  ],
@@ -1,8 +1,8 @@
1
1
  // src/entities/models.ts
2
2
  import {
3
- ScalarTypeEnum,
4
3
  defineEnum,
5
- defineSchemaModel
4
+ defineSchemaModel,
5
+ ScalarTypeEnum
6
6
  } from "@contractspec/lib.schema";
7
7
  var AllowedScopeEnum = defineEnum("AllowedScope", [
8
8
  "education_only",
@@ -1,8 +1,8 @@
1
1
  // src/entities/models.ts
2
2
  import {
3
- ScalarTypeEnum,
4
3
  defineEnum,
5
- defineSchemaModel
4
+ defineSchemaModel,
5
+ ScalarTypeEnum
6
6
  } from "@contractspec/lib.schema";
7
7
  var AllowedScopeEnum = defineEnum("AllowedScope", [
8
8
  "education_only",
@@ -1,6 +1,6 @@
1
1
  // src/events.ts
2
2
  import { defineEvent } from "@contractspec/lib.contracts-spec";
3
- import { ScalarTypeEnum, defineSchemaModel } from "@contractspec/lib.schema";
3
+ import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
4
4
  var AssistantAnswerRequestedPayload = defineSchemaModel({
5
5
  name: "AssistantAnswerRequestedPayload",
6
6
  description: "Emitted when an assistant answer is requested (pre-gate).",