@cosmicdrift/kumiko-framework 0.258.0 → 0.259.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.
Files changed (121) hide show
  1. package/package.json +3 -3
  2. package/src/__tests__/anonymous-access.integration.test.ts +3 -3
  3. package/src/__tests__/derived-fields.integration.test.ts +1 -1
  4. package/src/__tests__/entity-list-limits.integration.test.ts +1 -1
  5. package/src/__tests__/error-contract.integration.test.ts +1 -1
  6. package/src/__tests__/ownership-where-write-path.integration.test.ts +1 -1
  7. package/src/__tests__/ownership.integration.test.ts +7 -3
  8. package/src/__tests__/schema-cli-rebuild.integration.test.ts +2 -2
  9. package/src/__tests__/transition-guard.integration.test.ts +3 -3
  10. package/src/api/__tests__/api.test.ts +21 -3
  11. package/src/api/__tests__/batch.integration.test.ts +3 -3
  12. package/src/api/__tests__/body-limit.test.ts +7 -1
  13. package/src/api/__tests__/dispatcher-live.integration.test.ts +1 -1
  14. package/src/api/__tests__/http-route-rate-limit.integration.test.ts +7 -1
  15. package/src/api/__tests__/metrics-endpoint.test.ts +7 -1
  16. package/src/api/__tests__/nested-write.integration.test.ts +3 -3
  17. package/src/api/__tests__/server-boot-guards.test.ts +11 -4
  18. package/src/bun-db/__tests__/write-brand.test.ts +4 -1
  19. package/src/changes.json +6 -0
  20. package/src/db/__tests__/apply-entity-event-tenant.integration.test.ts +1 -1
  21. package/src/db/__tests__/assert-exists-in.integration.test.ts +1 -1
  22. package/src/db/__tests__/assert-no-unreachable-live-rows.integration.test.ts +2 -2
  23. package/src/db/__tests__/collect-table-metas.test.ts +9 -5
  24. package/src/db/__tests__/compound-types.test.ts +1 -1
  25. package/src/db/__tests__/config-seed.integration.test.ts +3 -3
  26. package/src/db/__tests__/eagerload.integration.test.ts +7 -7
  27. package/src/db/__tests__/entity-table-from-registry.test.ts +8 -2
  28. package/src/db/__tests__/entity-table-meta-source.test.ts +7 -3
  29. package/src/db/__tests__/entity-table-types.test.ts +4 -4
  30. package/src/db/__tests__/event-store-executor-list.integration.test.ts +9 -2
  31. package/src/db/__tests__/event-store-executor-reference-search.integration.test.ts +4 -4
  32. package/src/db/__tests__/event-store-executor-reference-sort.integration.test.ts +3 -3
  33. package/src/db/__tests__/event-store-executor-write-verbs.integration.test.ts +4 -4
  34. package/src/db/__tests__/event-store-executor.integration.test.ts +11 -6
  35. package/src/db/__tests__/event-store-system-stream.integration.test.ts +2 -2
  36. package/src/db/__tests__/implicit-projection-equivalence.integration.test.ts +6 -4
  37. package/src/db/__tests__/located-timestamp.test.ts +1 -1
  38. package/src/db/__tests__/money.test.ts +1 -1
  39. package/src/db/__tests__/multi-row-insert.integration.test.ts +3 -3
  40. package/src/db/__tests__/schema-migration.integration.test.ts +30 -14
  41. package/src/db/__tests__/source-shadow-create.integration.test.ts +1 -1
  42. package/src/db/__tests__/table-builder-indexes.test.ts +14 -12
  43. package/src/db/__tests__/table-builder-required.test.ts +2 -2
  44. package/src/db/__tests__/tenant-db-where-merge.integration.test.ts +1 -1
  45. package/src/db/__tests__/tenant-db-where-merge.test.ts +5 -2
  46. package/src/db/__tests__/tenant-db.integration.test.ts +2 -2
  47. package/src/db/__tests__/unique-violation-mapping.integration.test.ts +2 -2
  48. package/src/engine/__tests__/boot-validator-action-wiring.test.ts +50 -8
  49. package/src/engine/__tests__/boot-validator-dashboard.test.ts +138 -1
  50. package/src/engine/__tests__/boot-validator-detail-for.test.ts +28 -4
  51. package/src/engine/__tests__/boot-validator-entity-list.test.ts +20 -4
  52. package/src/engine/__tests__/boot-validator-i18n-keys.test.ts +9 -3
  53. package/src/engine/__tests__/boot-validator.test.ts +488 -91
  54. package/src/engine/__tests__/define-feature-entity-mapping.test.ts +2 -2
  55. package/src/engine/__tests__/engine.test.ts +128 -37
  56. package/src/engine/__tests__/entity-handlers.test.ts +3 -3
  57. package/src/engine/__tests__/entity-presave-wiring.integration.test.ts +4 -4
  58. package/src/engine/__tests__/entity-restore-tenant-isolation.integration.test.ts +1 -1
  59. package/src/engine/__tests__/entity-write-crosstenant.integration.test.ts +1 -1
  60. package/src/engine/__tests__/extend-entity-projection.test.ts +1 -1
  61. package/src/engine/__tests__/extends-registrar.test.ts +13 -3
  62. package/src/engine/__tests__/factories-long-text.test.ts +10 -6
  63. package/src/engine/__tests__/feature-crud-shorthand.test.ts +1 -1
  64. package/src/engine/__tests__/feature-crud-verb-access.integration.test.ts +1 -1
  65. package/src/engine/__tests__/multiselect-filter.integration.test.ts +1 -1
  66. package/src/engine/__tests__/nav.test.ts +1 -1
  67. package/src/engine/__tests__/pipeline-handler.integration.test.ts +1 -1
  68. package/src/engine/__tests__/pipeline-observability.integration.test.ts +1 -1
  69. package/src/engine/__tests__/pipeline-performance.integration.test.ts +1 -1
  70. package/src/engine/__tests__/projection-detail-actions.test.ts +6 -1
  71. package/src/engine/__tests__/projection-detail-singleton.test.ts +6 -1
  72. package/src/engine/__tests__/projection-detail-tabs.test.ts +6 -1
  73. package/src/engine/__tests__/projection-list-filter.integration.test.ts +7 -2
  74. package/src/engine/__tests__/projection.test.ts +1 -1
  75. package/src/engine/__tests__/registry.test.ts +13 -3
  76. package/src/engine/__tests__/schema-builder.test.ts +39 -11
  77. package/src/engine/__tests__/screen.test.ts +21 -15
  78. package/src/engine/__tests__/search-payload-extension.test.ts +15 -3
  79. package/src/engine/__tests__/store-table.test.ts +6 -3
  80. package/src/engine/__tests__/validate-projection-allowlist.test.ts +12 -4
  81. package/src/engine/__tests__/validation-hooks.test.ts +7 -1
  82. package/src/engine/boot-validator/__tests__/ownership.test.ts +2 -2
  83. package/src/engine/boot-validator/query-refs.ts +11 -0
  84. package/src/engine/boot-validator/screens.ts +45 -2
  85. package/src/engine/build-config-feature-schema.ts +2 -2
  86. package/src/engine/index.ts +2 -0
  87. package/src/engine/types/index.ts +2 -0
  88. package/src/es-ops/__tests__/runner.integration.test.ts +1 -1
  89. package/src/event-store/__tests__/upcaster.integration.test.ts +1 -1
  90. package/src/files/__tests__/file-field-pipeline.integration.test.ts +1 -1
  91. package/src/files/__tests__/files.integration.test.ts +1 -1
  92. package/src/files/file-ref-entity.ts +9 -9
  93. package/src/i18n/__tests__/i18n.test.ts +7 -1
  94. package/src/migrations/__tests__/kumiko-drift.integration.test.ts +3 -1
  95. package/src/migrations/__tests__/pending-rebuilds.integration.test.ts +2 -2
  96. package/src/pipeline/__tests__/archive-stream.integration.test.ts +1 -1
  97. package/src/pipeline/__tests__/cascade-handler.integration.test.ts +23 -8
  98. package/src/pipeline/__tests__/cascade-handler.test.ts +18 -3
  99. package/src/pipeline/__tests__/causation-chain.integration.test.ts +1 -1
  100. package/src/pipeline/__tests__/ctx-bridge.integration.test.ts +5 -3
  101. package/src/pipeline/__tests__/dispatcher.test.ts +42 -6
  102. package/src/pipeline/__tests__/domain-events-projections.integration.test.ts +2 -2
  103. package/src/pipeline/__tests__/fetch-for-writing.integration.test.ts +1 -1
  104. package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +42 -6
  105. package/src/pipeline/__tests__/load-aggregate-query.integration.test.ts +2 -2
  106. package/src/pipeline/__tests__/msp-multi-hop.integration.test.ts +1 -1
  107. package/src/pipeline/__tests__/msp-rebuild.integration.test.ts +6 -2
  108. package/src/pipeline/__tests__/multi-stream-projection.integration.test.ts +6 -2
  109. package/src/pipeline/__tests__/perf-rebuild.integration.test.ts +1 -1
  110. package/src/pipeline/__tests__/post-query-hook.integration.test.ts +3 -3
  111. package/src/pipeline/__tests__/projection-rebuild.integration.test.ts +3 -3
  112. package/src/pipeline/__tests__/query-projection.integration.test.ts +1 -1
  113. package/src/pipeline/__tests__/rebuild-poison-quarantine.integration.test.ts +2 -2
  114. package/src/pipeline/__tests__/search-consumer-named-events.integration.test.ts +13 -2
  115. package/src/pipeline/__tests__/try-append-event.integration.test.ts +1 -1
  116. package/src/search/__tests__/reindex-entity.integration.test.ts +6 -1
  117. package/src/search/__tests__/search-pii-derived-index.integration.test.ts +7 -1
  118. package/src/stack/__tests__/ownership-boot-guard.integration.test.ts +1 -1
  119. package/src/testing/__tests__/e2e-generator.test.ts +15 -5
  120. package/src/testing/shared-entities.ts +4 -2
  121. package/src/ui-types/index.ts +2 -0
@@ -5,11 +5,11 @@ import { createEntity, createTextField } from "../factories";
5
5
 
6
6
  const noteEntity = createEntity({
7
7
  table: "dfm_notes",
8
- fields: { title: createTextField({ required: true }) },
8
+ fields: { title: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
9
9
  });
10
10
  const tagEntity = createEntity({
11
11
  table: "dfm_tags",
12
- fields: { label: createTextField({ required: true }) },
12
+ fields: { label: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
13
13
  });
14
14
 
15
15
  const bareCreate = {
@@ -63,7 +63,7 @@ describe("defineFeature", () => {
63
63
  createEntity({
64
64
  table: "Users",
65
65
  fields: {
66
- email: createTextField({ searchable: true }),
66
+ email: createTextField({ searchable: true, personal: false, reason: "test_fixture" }),
67
67
  },
68
68
  }),
69
69
  );
@@ -331,7 +331,7 @@ describe("defineFeature", () => {
331
331
 
332
332
  describe("field factories", () => {
333
333
  test("createTextField has sensible defaults", () => {
334
- const field = createTextField();
334
+ const field = createTextField({ personal: false, reason: "test_fixture" });
335
335
  expect(field.type).toBe("text");
336
336
  expect(field.maxLength).toBe(200);
337
337
  expect(field.searchable).toBe(false);
@@ -339,7 +339,13 @@ describe("field factories", () => {
339
339
  });
340
340
 
341
341
  test("createTextField accepts overrides", () => {
342
- const field = createTextField({ searchable: true, maxLength: 500, format: "email" });
342
+ const field = createTextField({
343
+ searchable: true,
344
+ maxLength: 500,
345
+ format: "email",
346
+ personal: false,
347
+ reason: "test_fixture",
348
+ });
343
349
  expect(field.searchable).toBe(true);
344
350
  expect(field.maxLength).toBe(500);
345
351
  expect(field.format).toBe("email");
@@ -367,7 +373,9 @@ describe("createRegistry", () => {
367
373
  "user",
368
374
  createEntity({
369
375
  table: "Users",
370
- fields: { email: createTextField({ searchable: true }) },
376
+ fields: {
377
+ email: createTextField({ searchable: true, personal: false, reason: "test_fixture" }),
378
+ },
371
379
  }),
372
380
  );
373
381
  });
@@ -493,8 +501,12 @@ describe("createRegistry", () => {
493
501
  createEntity({
494
502
  table: "employees",
495
503
  fields: {
496
- name: createTextField(),
497
- salary: createTextField({ access: { write: ["Admin"] } }),
504
+ name: createTextField({ personal: false, reason: "test_fixture" }),
505
+ salary: createTextField({
506
+ access: { write: ["Admin"] },
507
+ personal: false,
508
+ reason: "test_fixture",
509
+ }),
498
510
  },
499
511
  }),
500
512
  );
@@ -509,7 +521,13 @@ describe("createRegistry", () => {
509
521
 
510
522
  test("allows unmapped write handlers when feature has no field-access rules", () => {
511
523
  const feature = defineFeature("admin", (r) => {
512
- r.entity("setting", createEntity({ table: "settings", fields: { key: createTextField() } }));
524
+ r.entity(
525
+ "setting",
526
+ createEntity({
527
+ table: "settings",
528
+ fields: { key: createTextField({ personal: false, reason: "test_fixture" }) },
529
+ }),
530
+ );
513
531
  // No field-access rules on entity → "reset" without entity prefix is fine
514
532
  r.writeHandler("reset", z.object({}), async () => ({ isSuccess: true, data: null }), {
515
533
  access: { openToAll: true },
@@ -526,8 +544,12 @@ describe("createRegistry", () => {
526
544
  createEntity({
527
545
  table: "employees",
528
546
  fields: {
529
- name: createTextField(),
530
- salary: createTextField({ access: { write: ["Admin"] } }),
547
+ name: createTextField({ personal: false, reason: "test_fixture" }),
548
+ salary: createTextField({
549
+ access: { write: ["Admin"] },
550
+ personal: false,
551
+ reason: "test_fixture",
552
+ }),
531
553
  },
532
554
  }),
533
555
  );
@@ -553,7 +575,11 @@ describe("createRegistry", () => {
553
575
  createEntity({
554
576
  table: "employees",
555
577
  fields: {
556
- salary: createTextField({ access: { read: ["Admin"] } }),
578
+ salary: createTextField({
579
+ access: { read: ["Admin"] },
580
+ personal: false,
581
+ reason: "test_fixture",
582
+ }),
557
583
  },
558
584
  }),
559
585
  );
@@ -580,7 +606,11 @@ describe("createRegistry", () => {
580
606
  createEntity({
581
607
  table: "employees",
582
608
  fields: {
583
- salary: createTextField({ access: { read: ["Admin"] } }),
609
+ salary: createTextField({
610
+ access: { read: ["Admin"] },
611
+ personal: false,
612
+ reason: "test_fixture",
613
+ }),
584
614
  },
585
615
  }),
586
616
  );
@@ -610,9 +640,13 @@ describe("createRegistry", () => {
610
640
  createEntity({
611
641
  table: "Users",
612
642
  fields: {
613
- email: createTextField({ searchable: true }),
614
- firstName: createTextField(),
615
- lastName: createTextField({ searchable: true }),
643
+ email: createTextField({ searchable: true, personal: false, reason: "test_fixture" }),
644
+ firstName: createTextField({ personal: false, reason: "test_fixture" }),
645
+ lastName: createTextField({
646
+ searchable: true,
647
+ personal: false,
648
+ reason: "test_fixture",
649
+ }),
616
650
  isEnabled: createBooleanField(),
617
651
  },
618
652
  }),
@@ -628,14 +662,17 @@ describe("createRegistry", () => {
628
662
  const feature = defineFeature("crm", (r) => {
629
663
  r.entity(
630
664
  "customer",
631
- createEntity({ table: "Customers", fields: { name: createTextField() } }),
665
+ createEntity({
666
+ table: "Customers",
667
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
668
+ }),
632
669
  );
633
670
  r.entity(
634
671
  "order",
635
672
  createEntity({
636
673
  table: "Orders",
637
674
  fields: {
638
- note: createTextField({ searchable: true }),
675
+ note: createTextField({ searchable: true, personal: false, reason: "test_fixture" }),
639
676
  customerId: {
640
677
  type: "reference",
641
678
  entity: "customer",
@@ -662,7 +699,10 @@ describe("createRegistry", () => {
662
699
  const feature = defineFeature("crm", (r) => {
663
700
  r.entity(
664
701
  "customer",
665
- createEntity({ table: "Customers", fields: { name: createTextField() } }),
702
+ createEntity({
703
+ table: "Customers",
704
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
705
+ }),
666
706
  );
667
707
  r.entity(
668
708
  "order",
@@ -680,7 +720,13 @@ describe("createRegistry", () => {
680
720
 
681
721
  test("throws at boot when searchable is combined with multiple on a reference field (fw#2660)", () => {
682
722
  const feature = defineFeature("crm", (r) => {
683
- r.entity("tag", createEntity({ table: "Tags", fields: { name: createTextField() } }));
723
+ r.entity(
724
+ "tag",
725
+ createEntity({
726
+ table: "Tags",
727
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
728
+ }),
729
+ );
684
730
  r.entity(
685
731
  "post",
686
732
  createEntity({
@@ -705,14 +751,17 @@ describe("createRegistry", () => {
705
751
  const feature = defineFeature("crm", (r) => {
706
752
  r.entity(
707
753
  "customer",
708
- createEntity({ table: "Customers", fields: { name: createTextField() } }),
754
+ createEntity({
755
+ table: "Customers",
756
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
757
+ }),
709
758
  );
710
759
  r.entity(
711
760
  "order",
712
761
  createEntity({
713
762
  table: "Orders",
714
763
  fields: {
715
- note: createTextField({ sortable: true }),
764
+ note: createTextField({ sortable: true, personal: false, reason: "test_fixture" }),
716
765
  customerId: {
717
766
  type: "reference",
718
767
  entity: "customer",
@@ -736,7 +785,13 @@ describe("createRegistry", () => {
736
785
 
737
786
  test("resolves a cross-feature sortable reference to its bare entity name (fw#2741)", () => {
738
787
  const users = defineFeature("users", (r) => {
739
- r.entity("user", createEntity({ table: "Users", fields: { email: createTextField() } }));
788
+ r.entity(
789
+ "user",
790
+ createEntity({
791
+ table: "Users",
792
+ fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
793
+ }),
794
+ );
740
795
  });
741
796
  const crm = defineFeature("crm", (r) => {
742
797
  r.entity(
@@ -765,7 +820,10 @@ describe("createRegistry", () => {
765
820
  const feature = defineFeature("crm", (r) => {
766
821
  r.entity(
767
822
  "customer",
768
- createEntity({ table: "Customers", fields: { name: createTextField() } }),
823
+ createEntity({
824
+ table: "Customers",
825
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
826
+ }),
769
827
  );
770
828
  r.entity(
771
829
  "order",
@@ -785,7 +843,10 @@ describe("createRegistry", () => {
785
843
  const feature = defineFeature("crm", (r) => {
786
844
  r.entity(
787
845
  "customer",
788
- createEntity({ table: "Customers", fields: { name: createTextField() } }),
846
+ createEntity({
847
+ table: "Customers",
848
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
849
+ }),
789
850
  );
790
851
  r.entity(
791
852
  "order",
@@ -808,7 +869,13 @@ describe("createRegistry", () => {
808
869
 
809
870
  test("throws at boot when sortable is combined with multiple on a reference field (fw#2741)", () => {
810
871
  const feature = defineFeature("crm", (r) => {
811
- r.entity("tag", createEntity({ table: "Tags", fields: { name: createTextField() } }));
872
+ r.entity(
873
+ "tag",
874
+ createEntity({
875
+ table: "Tags",
876
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
877
+ }),
878
+ );
812
879
  r.entity(
813
880
  "post",
814
881
  createEntity({
@@ -883,12 +950,12 @@ describe("entity options", () => {
883
950
 
884
951
  describe("sortable fields", () => {
885
952
  test("createTextField supports sortable property", () => {
886
- const field = createTextField({ sortable: true });
953
+ const field = createTextField({ sortable: true, personal: false, reason: "test_fixture" });
887
954
  expect(field.sortable).toBe(true);
888
955
  });
889
956
 
890
957
  test("sortable defaults to false", () => {
891
- const field = createTextField();
958
+ const field = createTextField({ personal: false, reason: "test_fixture" });
892
959
  expect(field.sortable).toBe(false);
893
960
  });
894
961
 
@@ -899,9 +966,9 @@ describe("sortable fields", () => {
899
966
  createEntity({
900
967
  table: "Items",
901
968
  fields: {
902
- name: createTextField({ sortable: true }),
903
- email: createTextField(),
904
- rank: createTextField({ sortable: true }),
969
+ name: createTextField({ sortable: true, personal: false, reason: "test_fixture" }),
970
+ email: createTextField({ personal: false, reason: "test_fixture" }),
971
+ rank: createTextField({ sortable: true, personal: false, reason: "test_fixture" }),
905
972
  },
906
973
  }),
907
974
  );
@@ -984,7 +1051,13 @@ describe("createApp", () => {
984
1051
 
985
1052
  test("softDeleteDefault is true by default, configurable via softDelete", () => {
986
1053
  const feature = defineFeature("test", (r) => {
987
- r.entity("item", createEntity({ table: "Items", fields: { name: createTextField() } }));
1054
+ r.entity(
1055
+ "item",
1056
+ createEntity({
1057
+ table: "Items",
1058
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
1059
+ }),
1060
+ );
988
1061
  });
989
1062
 
990
1063
  const app1 = createApp({ roles: ["Admin"], features: [feature] });
@@ -1319,7 +1392,7 @@ describe("createApp", () => {
1319
1392
  createEntity({
1320
1393
  table: "Invoices",
1321
1394
  fields: {
1322
- title: createTextField(),
1395
+ title: createTextField({ personal: false, reason: "test_fixture" }),
1323
1396
  lines: createEmbeddedListField(
1324
1397
  { amount: { type: "money" } },
1325
1398
  { totalsMatch: { amount: "title" } },
@@ -1403,7 +1476,7 @@ describe("createApp", () => {
1403
1476
  "doc",
1404
1477
  createEntity({
1405
1478
  table: "Docs",
1406
- fields: { title: createTextField() },
1479
+ fields: { title: createTextField({ personal: false, reason: "test_fixture" }) },
1407
1480
  transitions: {
1408
1481
  title: { a: ["b"] },
1409
1482
  },
@@ -1443,7 +1516,7 @@ describe("createApp", () => {
1443
1516
  "doc",
1444
1517
  createEntity({
1445
1518
  table: "Docs",
1446
- fields: { title: createTextField() },
1519
+ fields: { title: createTextField({ personal: false, reason: "test_fixture" }) },
1447
1520
  transitions: {
1448
1521
  nonExistent: { a: ["b"] },
1449
1522
  },
@@ -1794,11 +1867,17 @@ describe("r.relation()", () => {
1794
1867
  const feature = defineFeature("test", (r) => {
1795
1868
  r.entity(
1796
1869
  "user",
1797
- createEntity({ table: "Users", fields: { departmentId: createTextField() } }),
1870
+ createEntity({
1871
+ table: "Users",
1872
+ fields: { departmentId: createTextField({ personal: false, reason: "test_fixture" }) },
1873
+ }),
1798
1874
  );
1799
1875
  r.entity(
1800
1876
  "department",
1801
- createEntity({ table: "Departments", fields: { name: createTextField() } }),
1877
+ createEntity({
1878
+ table: "Departments",
1879
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
1880
+ }),
1802
1881
  );
1803
1882
  r.relation("user", "department", {
1804
1883
  type: "belongsTo",
@@ -1814,7 +1893,13 @@ describe("r.relation()", () => {
1814
1893
  test("registers manyToMany relation", () => {
1815
1894
  const feature = defineFeature("test", (r) => {
1816
1895
  r.entity("user", createEntity({ table: "Users", fields: {} }));
1817
- r.entity("role", createEntity({ table: "Roles", fields: { name: createTextField() } }));
1896
+ r.entity(
1897
+ "role",
1898
+ createEntity({
1899
+ table: "Roles",
1900
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
1901
+ }),
1902
+ );
1818
1903
  r.relation("user", "roles", {
1819
1904
  type: "manyToMany",
1820
1905
  target: "role",
@@ -1848,7 +1933,13 @@ describe("registry relations", () => {
1848
1933
  test("getRelations returns relations within same feature", () => {
1849
1934
  const f1 = defineFeature("users", (r) => {
1850
1935
  r.entity("user", createEntity({ table: "Users", fields: {} }));
1851
- r.entity("role", createEntity({ table: "Roles", fields: { name: createTextField() } }));
1936
+ r.entity(
1937
+ "role",
1938
+ createEntity({
1939
+ table: "Roles",
1940
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
1941
+ }),
1942
+ );
1852
1943
  r.relation("user", "roles", {
1853
1944
  type: "manyToMany",
1854
1945
  target: "role",
@@ -24,15 +24,15 @@ const VALID_UUID = "00000000-0000-4000-8000-000000000001";
24
24
  const noteEntity = createEntity({
25
25
  table: "notes",
26
26
  fields: {
27
- title: createTextField({ required: true }),
28
- body: createTextField(),
27
+ title: createTextField({ required: true, personal: false, reason: "test_fixture" }),
28
+ body: createTextField({ personal: false, reason: "test_fixture" }),
29
29
  },
30
30
  });
31
31
 
32
32
  const noteEntitySoftDelete = createEntity({
33
33
  table: "notes_soft",
34
34
  fields: {
35
- title: createTextField({ required: true }),
35
+ title: createTextField({ required: true, personal: false, reason: "test_fixture" }),
36
36
  },
37
37
  softDelete: true,
38
38
  });
@@ -13,9 +13,9 @@ import { from } from "../ownership";
13
13
  const contactEntity = createEntity({
14
14
  table: "presave_wiring_contacts",
15
15
  fields: {
16
- firstName: createTextField({ required: true }),
17
- lastName: createTextField({ required: true }),
18
- displayName: createTextField(),
16
+ firstName: createTextField({ required: true, personal: false, reason: "test_fixture" }),
17
+ lastName: createTextField({ required: true, personal: false, reason: "test_fixture" }),
18
+ displayName: createTextField({ personal: false, reason: "test_fixture" }),
19
19
  // authorId is never set by the client — only deriveAuthorId (a preSave
20
20
  // hook) writes it. secretNote's ownership rule checks authorId, so
21
21
  // create only succeeds if the hook ran BEFORE the field-ownership check
@@ -64,7 +64,7 @@ const contactFeature = defineFeature("presave-wiring", (r) => {
64
64
 
65
65
  const throwingEntity = createEntity({
66
66
  table: "presave_wiring_throwing",
67
- fields: { name: createTextField({ required: true }) },
67
+ fields: { name: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
68
68
  });
69
69
 
70
70
  const throwingFeature = defineFeature("presave-wiring-throw", (r) => {
@@ -33,7 +33,7 @@ const thingEntity = createEntity({
33
33
  table: "ctrestore_things",
34
34
  softDelete: true,
35
35
  fields: {
36
- label: createTextField({ required: true }),
36
+ label: createTextField({ required: true, personal: false, reason: "test_fixture" }),
37
37
  },
38
38
  access: { write: { Admin: "all", SystemAdmin: from("user:tenantId", "tenantId") } },
39
39
  });
@@ -38,7 +38,7 @@ import {
38
38
  const thingEntity = createEntity({
39
39
  table: "ctwrite_things",
40
40
  fields: {
41
- label: createTextField({ required: true }),
41
+ label: createTextField({ required: true, personal: false, reason: "test_fixture" }),
42
42
  },
43
43
  access: { write: { Admin: "all", SystemAdmin: from("user:tenantId", "tenantId") } },
44
44
  });
@@ -11,7 +11,7 @@ import { createRegistry } from "../registry";
11
11
  function exampleEntity(name = "unit") {
12
12
  return createEntity({
13
13
  table: name,
14
- fields: { name: createTextField() },
14
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
15
15
  });
16
16
  }
17
17
 
@@ -85,7 +85,7 @@ describe("extendsRegistrar", () => {
85
85
  "vehicle",
86
86
  createEntity({
87
87
  table: "Vehicles",
88
- fields: { name: createTextField() },
88
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
89
89
  }),
90
90
  );
91
91
  r.useExtension("customFields", "vehicle");
@@ -108,7 +108,13 @@ describe("extendsRegistrar", () => {
108
108
  });
109
109
  const consumer = defineFeature("credit", (r) => {
110
110
  r.requires("audit");
111
- r.entity("credit", createEntity({ table: "Credits", fields: { name: createTextField() } }));
111
+ r.entity(
112
+ "credit",
113
+ createEntity({
114
+ table: "Credits",
115
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
116
+ }),
117
+ );
112
118
  r.writeHandler("create", z.object({ name: z.string() }), async () => ({
113
119
  isSuccess: true as const,
114
120
  data: { id: "c1" },
@@ -134,7 +140,11 @@ describe("extendsRegistrar", () => {
134
140
  const consumer = defineFeature("fleet", (r) => {
135
141
  r.entity(
136
142
  "vehicle",
137
- createEntity({ table: "Vehicles", idType: "uuid", fields: { name: createTextField() } }),
143
+ createEntity({
144
+ table: "Vehicles",
145
+ idType: "uuid",
146
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
147
+ }),
138
148
  );
139
149
  // Explicit handlers — the entity mapping is inferred from the
140
150
  // "vehicle:" prefix via tryMapEntity, so the extension's preSave
@@ -23,7 +23,7 @@ describe("createLongTextField — runtime shape", () => {
23
23
  });
24
24
 
25
25
  test("required: true is preserved as literal in the return type", () => {
26
- const f = createLongTextField({ required: true });
26
+ const f = createLongTextField({ required: true, personal: false, reason: "test_fixture" });
27
27
  expect(f.required).toBe(true);
28
28
  // Literal-type-pin: TypeScript should narrow `required` to `true`,
29
29
  // not `boolean`. If this test compiles with `f.required: boolean`,
@@ -32,7 +32,11 @@ describe("createLongTextField — runtime shape", () => {
32
32
  });
33
33
 
34
34
  test("maxLength is propagated through", () => {
35
- const f = createLongTextField({ maxLength: 1_000_000 });
35
+ const f = createLongTextField({
36
+ maxLength: 1_000_000,
37
+ personal: false,
38
+ reason: "test_fixture",
39
+ });
36
40
  expect(f.maxLength).toBe(1_000_000);
37
41
  });
38
42
 
@@ -55,13 +59,13 @@ describe("LongTextFieldDef — type-level non-indexable enforcement", () => {
55
59
  // back to LongTextFieldDef, the @ts-expect-error fails (because
56
60
  // the call would suddenly type-check), turning the test red.
57
61
  // @ts-expect-error sortable is NOT allowed on longText
58
- const f1 = createLongTextField({ sortable: true });
62
+ const f1 = createLongTextField({ sortable: true, personal: false, reason: "test_fixture" });
59
63
  // @ts-expect-error searchable is NOT allowed on longText
60
- const f2 = createLongTextField({ searchable: true });
64
+ const f2 = createLongTextField({ searchable: true, personal: false, reason: "test_fixture" });
61
65
  // @ts-expect-error filterable is NOT allowed on longText
62
- const f3 = createLongTextField({ filterable: true });
66
+ const f3 = createLongTextField({ filterable: true, personal: false, reason: "test_fixture" });
63
67
  // @ts-expect-error format is NOT allowed on longText
64
- const f4 = createLongTextField({ format: "email" });
68
+ const f4 = createLongTextField({ format: "email", personal: false, reason: "test_fixture" });
65
69
 
66
70
  // Runtime sanity: trotz der @ts-expect-error-ignored options ist
67
71
  // das field zur Laufzeit erfolgreich erzeugt — type-level-blockade
@@ -4,7 +4,7 @@ import { createEntity, createTextField } from "../factories";
4
4
 
5
5
  const taskEntity = createEntity({
6
6
  table: "crud_shorthand_tasks",
7
- fields: { title: createTextField({ required: true }) },
7
+ fields: { title: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
8
8
  softDelete: true,
9
9
  });
10
10
 
@@ -6,7 +6,7 @@ import { createEntity, createTextField } from "../factories";
6
6
 
7
7
  const propertyEntity = createEntity({
8
8
  table: "crud_verb_access_properties",
9
- fields: { title: createTextField({ required: true }) },
9
+ fields: { title: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
10
10
  softDelete: true,
11
11
  });
12
12
 
@@ -15,7 +15,7 @@ import { createEntity, createMultiSelectField, createTextField } from "../factor
15
15
  const equipmentEntity = createEntity({
16
16
  table: "ms_filter_equipment",
17
17
  fields: {
18
- name: createTextField({ required: true }),
18
+ name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
19
19
  tags: createMultiSelectField({
20
20
  options: ["vip", "urgent", "loaner"] as const,
21
21
  filterable: true,
@@ -12,7 +12,7 @@ function validateBoot(features: Parameters<typeof validateBootRaw>[0]): void {
12
12
  function productEntity() {
13
13
  return createEntity({
14
14
  table: "products",
15
- fields: { name: createTextField() },
15
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
16
16
  });
17
17
  }
18
18
 
@@ -170,7 +170,7 @@ const logHandler = defineWriteHandler({
170
170
  // unsafeProjection.* that targets it).
171
171
  const widgetEntity = createEntity({
172
172
  table: "pipeline_widget",
173
- fields: { label: createTextField({ required: true }) },
173
+ fields: { label: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
174
174
  });
175
175
  const widgetTable = buildEntityTable("widget", widgetEntity);
176
176
  const widgetExecutor = createEventStoreExecutor(widgetTable, widgetEntity, {
@@ -52,7 +52,7 @@ const observedHandler = defineWriteHandler({
52
52
 
53
53
  const obsEntity = createEntity({
54
54
  table: "obs_smoke_things",
55
- fields: { label: createTextField({ required: true }) },
55
+ fields: { label: createTextField({ required: true, personal: false, reason: "test_fixture" }) },
56
56
  });
57
57
 
58
58
  const obsFeature = defineFeature("obstest", (r) => {
@@ -62,7 +62,7 @@ const trivialFreeform = defineWriteHandler({
62
62
  const productEntity = createEntity({
63
63
  table: "perf_smoke_products",
64
64
  fields: {
65
- sku: createTextField({ required: true }),
65
+ sku: createTextField({ required: true, personal: false, reason: "test_fixture" }),
66
66
  qty: createNumberField({ default: 0 }),
67
67
  },
68
68
  });
@@ -87,7 +87,12 @@ describe("validateBoot — projectionDetail actions (fw#2166)", () => {
87
87
 
88
88
  test("navigate action with params targeting an entityEdit of the SAME entity (via detailFor) throws — params are a no-op on an update target (review finding 3b)", () => {
89
89
  const feature = defineFeature("app", (r) => {
90
- r.entity("rent", createEntity({ fields: { name: createTextField() } }));
90
+ r.entity(
91
+ "rent",
92
+ createEntity({
93
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
94
+ }),
95
+ );
91
96
  r.screen({
92
97
  id: "rent-detail",
93
98
  type: "projectionDetail",
@@ -39,7 +39,12 @@ describe("validateBoot — projectionDetail singleton (fw#2312)", () => {
39
39
 
40
40
  test("singleton + detailFor throws", () => {
41
41
  const feature = defineFeature("app", (r) => {
42
- r.entity("user", createEntity({ fields: { name: createTextField() } }));
42
+ r.entity(
43
+ "user",
44
+ createEntity({
45
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
46
+ }),
47
+ );
43
48
  r.queryHandler("me", z.object({}), async () => ({ id: "u1" }), {
44
49
  access: { openToAll: true },
45
50
  });
@@ -100,7 +100,12 @@ describe("validateBoot — projectionDetail tabs (fw record-layout)", () => {
100
100
 
101
101
  test("mode: tabs on entityEdit throws — tabs are projectionDetail-only", () => {
102
102
  const feature = defineFeature("app", (r) => {
103
- r.entity("rent", createEntity({ fields: { name: createTextField() } }));
103
+ r.entity(
104
+ "rent",
105
+ createEntity({
106
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
107
+ }),
108
+ );
104
109
  r.screen({
105
110
  id: "rent-edit",
106
111
  type: "entityEdit",
@@ -22,8 +22,13 @@ import { createEntity, createTextField } from "../factories";
22
22
  const memberEntity = createEntity({
23
23
  table: "pl_filter_members",
24
24
  fields: {
25
- name: createTextField({ required: true }),
26
- status: createTextField({ required: true, filterable: true }),
25
+ name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
26
+ status: createTextField({
27
+ required: true,
28
+ filterable: true,
29
+ personal: false,
30
+ reason: "test_fixture",
31
+ }),
27
32
  },
28
33
  });
29
34