@cosmicdrift/kumiko-framework 0.258.0 → 0.258.1

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 (114) 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/db/__tests__/apply-entity-event-tenant.integration.test.ts +1 -1
  20. package/src/db/__tests__/assert-exists-in.integration.test.ts +1 -1
  21. package/src/db/__tests__/assert-no-unreachable-live-rows.integration.test.ts +2 -2
  22. package/src/db/__tests__/collect-table-metas.test.ts +9 -5
  23. package/src/db/__tests__/compound-types.test.ts +1 -1
  24. package/src/db/__tests__/config-seed.integration.test.ts +3 -3
  25. package/src/db/__tests__/eagerload.integration.test.ts +7 -7
  26. package/src/db/__tests__/entity-table-from-registry.test.ts +8 -2
  27. package/src/db/__tests__/entity-table-meta-source.test.ts +7 -3
  28. package/src/db/__tests__/entity-table-types.test.ts +4 -4
  29. package/src/db/__tests__/event-store-executor-list.integration.test.ts +9 -2
  30. package/src/db/__tests__/event-store-executor-reference-search.integration.test.ts +4 -4
  31. package/src/db/__tests__/event-store-executor-reference-sort.integration.test.ts +3 -3
  32. package/src/db/__tests__/event-store-executor-write-verbs.integration.test.ts +4 -4
  33. package/src/db/__tests__/event-store-executor.integration.test.ts +11 -6
  34. package/src/db/__tests__/event-store-system-stream.integration.test.ts +2 -2
  35. package/src/db/__tests__/implicit-projection-equivalence.integration.test.ts +6 -4
  36. package/src/db/__tests__/located-timestamp.test.ts +1 -1
  37. package/src/db/__tests__/money.test.ts +1 -1
  38. package/src/db/__tests__/multi-row-insert.integration.test.ts +3 -3
  39. package/src/db/__tests__/schema-migration.integration.test.ts +30 -14
  40. package/src/db/__tests__/source-shadow-create.integration.test.ts +1 -1
  41. package/src/db/__tests__/table-builder-indexes.test.ts +14 -12
  42. package/src/db/__tests__/table-builder-required.test.ts +2 -2
  43. package/src/db/__tests__/tenant-db-where-merge.integration.test.ts +1 -1
  44. package/src/db/__tests__/tenant-db-where-merge.test.ts +5 -2
  45. package/src/db/__tests__/tenant-db.integration.test.ts +2 -2
  46. package/src/db/__tests__/unique-violation-mapping.integration.test.ts +2 -2
  47. package/src/engine/__tests__/boot-validator-action-wiring.test.ts +50 -8
  48. package/src/engine/__tests__/boot-validator-detail-for.test.ts +28 -4
  49. package/src/engine/__tests__/boot-validator-entity-list.test.ts +20 -4
  50. package/src/engine/__tests__/boot-validator-i18n-keys.test.ts +9 -3
  51. package/src/engine/__tests__/boot-validator.test.ts +488 -91
  52. package/src/engine/__tests__/define-feature-entity-mapping.test.ts +2 -2
  53. package/src/engine/__tests__/engine.test.ts +128 -37
  54. package/src/engine/__tests__/entity-handlers.test.ts +3 -3
  55. package/src/engine/__tests__/entity-presave-wiring.integration.test.ts +4 -4
  56. package/src/engine/__tests__/entity-restore-tenant-isolation.integration.test.ts +1 -1
  57. package/src/engine/__tests__/entity-write-crosstenant.integration.test.ts +1 -1
  58. package/src/engine/__tests__/extend-entity-projection.test.ts +1 -1
  59. package/src/engine/__tests__/extends-registrar.test.ts +13 -3
  60. package/src/engine/__tests__/factories-long-text.test.ts +10 -6
  61. package/src/engine/__tests__/feature-crud-shorthand.test.ts +1 -1
  62. package/src/engine/__tests__/feature-crud-verb-access.integration.test.ts +1 -1
  63. package/src/engine/__tests__/multiselect-filter.integration.test.ts +1 -1
  64. package/src/engine/__tests__/nav.test.ts +1 -1
  65. package/src/engine/__tests__/pipeline-handler.integration.test.ts +1 -1
  66. package/src/engine/__tests__/pipeline-observability.integration.test.ts +1 -1
  67. package/src/engine/__tests__/pipeline-performance.integration.test.ts +1 -1
  68. package/src/engine/__tests__/projection-detail-actions.test.ts +6 -1
  69. package/src/engine/__tests__/projection-detail-singleton.test.ts +6 -1
  70. package/src/engine/__tests__/projection-detail-tabs.test.ts +6 -1
  71. package/src/engine/__tests__/projection-list-filter.integration.test.ts +7 -2
  72. package/src/engine/__tests__/projection.test.ts +1 -1
  73. package/src/engine/__tests__/registry.test.ts +13 -3
  74. package/src/engine/__tests__/schema-builder.test.ts +39 -11
  75. package/src/engine/__tests__/screen.test.ts +21 -15
  76. package/src/engine/__tests__/search-payload-extension.test.ts +15 -3
  77. package/src/engine/__tests__/store-table.test.ts +6 -3
  78. package/src/engine/__tests__/validate-projection-allowlist.test.ts +12 -4
  79. package/src/engine/__tests__/validation-hooks.test.ts +7 -1
  80. package/src/engine/boot-validator/__tests__/ownership.test.ts +2 -2
  81. package/src/engine/build-config-feature-schema.ts +2 -2
  82. package/src/es-ops/__tests__/runner.integration.test.ts +1 -1
  83. package/src/event-store/__tests__/upcaster.integration.test.ts +1 -1
  84. package/src/files/__tests__/file-field-pipeline.integration.test.ts +1 -1
  85. package/src/files/__tests__/files.integration.test.ts +1 -1
  86. package/src/files/file-ref-entity.ts +9 -9
  87. package/src/i18n/__tests__/i18n.test.ts +7 -1
  88. package/src/migrations/__tests__/kumiko-drift.integration.test.ts +3 -1
  89. package/src/migrations/__tests__/pending-rebuilds.integration.test.ts +2 -2
  90. package/src/pipeline/__tests__/archive-stream.integration.test.ts +1 -1
  91. package/src/pipeline/__tests__/cascade-handler.integration.test.ts +23 -8
  92. package/src/pipeline/__tests__/cascade-handler.test.ts +18 -3
  93. package/src/pipeline/__tests__/causation-chain.integration.test.ts +1 -1
  94. package/src/pipeline/__tests__/ctx-bridge.integration.test.ts +5 -3
  95. package/src/pipeline/__tests__/dispatcher.test.ts +42 -6
  96. package/src/pipeline/__tests__/domain-events-projections.integration.test.ts +2 -2
  97. package/src/pipeline/__tests__/fetch-for-writing.integration.test.ts +1 -1
  98. package/src/pipeline/__tests__/lifecycle-pipeline.test.ts +42 -6
  99. package/src/pipeline/__tests__/load-aggregate-query.integration.test.ts +2 -2
  100. package/src/pipeline/__tests__/msp-multi-hop.integration.test.ts +1 -1
  101. package/src/pipeline/__tests__/msp-rebuild.integration.test.ts +6 -2
  102. package/src/pipeline/__tests__/multi-stream-projection.integration.test.ts +6 -2
  103. package/src/pipeline/__tests__/perf-rebuild.integration.test.ts +1 -1
  104. package/src/pipeline/__tests__/post-query-hook.integration.test.ts +3 -3
  105. package/src/pipeline/__tests__/projection-rebuild.integration.test.ts +3 -3
  106. package/src/pipeline/__tests__/query-projection.integration.test.ts +1 -1
  107. package/src/pipeline/__tests__/rebuild-poison-quarantine.integration.test.ts +2 -2
  108. package/src/pipeline/__tests__/search-consumer-named-events.integration.test.ts +13 -2
  109. package/src/pipeline/__tests__/try-append-event.integration.test.ts +1 -1
  110. package/src/search/__tests__/reindex-entity.integration.test.ts +6 -1
  111. package/src/search/__tests__/search-pii-derived-index.integration.test.ts +7 -1
  112. package/src/stack/__tests__/ownership-boot-guard.integration.test.ts +1 -1
  113. package/src/testing/__tests__/e2e-generator.test.ts +15 -5
  114. package/src/testing/shared-entities.ts +4 -2
@@ -17,7 +17,7 @@ const testTable = table("test_projection", {
17
17
  function exampleEntity(name = "unit") {
18
18
  return createEntity({
19
19
  table: name,
20
- fields: { name: createTextField() },
20
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
21
21
  });
22
22
  }
23
23
 
@@ -65,11 +65,15 @@ describe("getAllQueryHandlers", () => {
65
65
  test("returns every registered query handler, qualified, across multiple features", () => {
66
66
  const taskEntity = createEntity({
67
67
  table: "registry_test_tasks",
68
- fields: { title: createTextField({ required: true }) },
68
+ fields: {
69
+ title: createTextField({ required: true, personal: false, reason: "test_fixture" }),
70
+ },
69
71
  });
70
72
  const noteEntity = createEntity({
71
73
  table: "registry_test_notes",
72
- fields: { body: createTextField({ required: true }) },
74
+ fields: {
75
+ body: createTextField({ required: true, personal: false, reason: "test_fixture" }),
76
+ },
73
77
  });
74
78
  const taskFeature = defineFeature("registry-test-task", (r) => {
75
79
  r.crud("task", taskEntity, {
@@ -283,7 +287,13 @@ describe("extensionSelector boot-validation", () => {
283
287
  });
284
288
  const consumer = defineFeature("money-horse", (r) => {
285
289
  r.requires("cap-ext");
286
- r.entity("credit", createEntity({ table: "Credits", fields: { name: createTextField() } }));
290
+ r.entity(
291
+ "credit",
292
+ createEntity({
293
+ table: "Credits",
294
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
295
+ }),
296
+ );
287
297
  r.writeHandler(
288
298
  "doSomething",
289
299
  z.object({}),
@@ -32,25 +32,34 @@ describe("buildInsertSchema", () => {
32
32
  test.each<SchemaCase>([
33
33
  {
34
34
  name: "required text field",
35
- fields: { email: createTextField({ required: true }) },
35
+ fields: {
36
+ email: createTextField({ required: true, personal: false, reason: "test_fixture" }),
37
+ },
36
38
  valid: { email: "test@test.de" },
37
39
  invalid: { email: "" },
38
40
  },
39
41
  {
40
42
  name: "optional text field",
41
- fields: { name: createTextField() },
43
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
42
44
  valid: {},
43
45
  invalid: null,
44
46
  },
45
47
  {
46
48
  name: "text field with maxLength",
47
- fields: { name: createTextField({ maxLength: 5 }) },
49
+ fields: { name: createTextField({ maxLength: 5, personal: false, reason: "test_fixture" }) },
48
50
  valid: { name: "hello" },
49
51
  invalid: { name: "toolong" },
50
52
  },
51
53
  {
52
54
  name: "email format",
53
- fields: { email: createTextField({ required: true, format: "email" }) },
55
+ fields: {
56
+ email: createTextField({
57
+ required: true,
58
+ format: "email",
59
+ personal: false,
60
+ reason: "test_fixture",
61
+ }),
62
+ },
54
63
  valid: { email: "a@b.de" },
55
64
  invalid: { email: "not-an-email" },
56
65
  },
@@ -166,8 +175,13 @@ describe("buildInsertSchema", () => {
166
175
  const entity = createEntity({
167
176
  table: "Users",
168
177
  fields: {
169
- email: createTextField({ required: true, format: "email" }),
170
- firstName: createTextField(),
178
+ email: createTextField({
179
+ required: true,
180
+ format: "email",
181
+ personal: false,
182
+ reason: "test_fixture",
183
+ }),
184
+ firstName: createTextField({ personal: false, reason: "test_fixture" }),
171
185
  isEnabled: createBooleanField({ default: true }),
172
186
  locale: createSelectField({ options: ["de", "en"] as const }),
173
187
  },
@@ -281,7 +295,9 @@ describe("buildInsertSchema", () => {
281
295
  test("required text rejects empty string", () => {
282
296
  const entity = createEntity({
283
297
  table: "Test",
284
- fields: { name: createTextField({ required: true }) },
298
+ fields: {
299
+ name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
300
+ },
285
301
  });
286
302
  const schema = buildInsertSchema(entity);
287
303
  expect(schema.safeParse({ name: "" }).success).toBe(false);
@@ -353,7 +369,7 @@ describe("buildInsertSchema", () => {
353
369
  const entity = createEntity({
354
370
  table: "Test",
355
371
  fields: {
356
- name: createTextField({ required: true }),
372
+ name: createTextField({ required: true, personal: false, reason: "test_fixture" }),
357
373
  address: createEmbeddedField({ street: { type: "text" } }),
358
374
  },
359
375
  });
@@ -1061,8 +1077,13 @@ describe("buildUpdateSchema", () => {
1061
1077
  const entity = createEntity({
1062
1078
  table: "Users",
1063
1079
  fields: {
1064
- email: createTextField({ required: true, format: "email" }),
1065
- firstName: createTextField(),
1080
+ email: createTextField({
1081
+ required: true,
1082
+ format: "email",
1083
+ personal: false,
1084
+ reason: "test_fixture",
1085
+ }),
1086
+ firstName: createTextField({ personal: false, reason: "test_fixture" }),
1066
1087
  isEnabled: createBooleanField(),
1067
1088
  },
1068
1089
  });
@@ -1082,7 +1103,14 @@ describe("buildUpdateSchema", () => {
1082
1103
  test("still validates format on provided fields", () => {
1083
1104
  const entity = createEntity({
1084
1105
  table: "Users",
1085
- fields: { email: createTextField({ required: true, format: "email" }) },
1106
+ fields: {
1107
+ email: createTextField({
1108
+ required: true,
1109
+ format: "email",
1110
+ personal: false,
1111
+ reason: "test_fixture",
1112
+ }),
1113
+ },
1086
1114
  });
1087
1115
 
1088
1116
  const schema = buildUpdateSchema(entity);
@@ -16,8 +16,8 @@ function productEntity() {
16
16
  return createEntity({
17
17
  table: "products",
18
18
  fields: {
19
- name: createTextField(),
20
- sku: createTextField(),
19
+ name: createTextField({ personal: false, reason: "test_fixture" }),
20
+ sku: createTextField({ personal: false, reason: "test_fixture" }),
21
21
  },
22
22
  });
23
23
  }
@@ -26,7 +26,7 @@ function derivedProductEntity() {
26
26
  return createEntity({
27
27
  table: "derived_products",
28
28
  fields: {
29
- name: createTextField(),
29
+ name: createTextField({ personal: false, reason: "test_fixture" }),
30
30
  },
31
31
  derivedFields: {
32
32
  summary: createDerivedField({
@@ -306,7 +306,10 @@ describe("r.screen() — registration", () => {
306
306
  defineFeature("billing", (r) => {
307
307
  r.entity(
308
308
  "invoice",
309
- createEntity({ table: "invoices", fields: { name: createTextField() } }),
309
+ createEntity({
310
+ table: "invoices",
311
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
312
+ }),
310
313
  );
311
314
  r.screen({
312
315
  id: "invoice-detail",
@@ -695,7 +698,10 @@ describe("r.screen() — registration", () => {
695
698
  defineFeature("billing", (r) => {
696
699
  r.entity(
697
700
  "invoice",
698
- createEntity({ table: "invoices", fields: { name: createTextField() } }),
701
+ createEntity({
702
+ table: "invoices",
703
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
704
+ }),
699
705
  );
700
706
  r.screen({
701
707
  id: "invoice-detail",
@@ -774,7 +780,7 @@ describe("r.screen() — registration", () => {
774
780
  {
775
781
  kind: "writeForm",
776
782
  title: "s",
777
- fieldDefs: { name: createTextField() },
783
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
778
784
  fields: [],
779
785
  handler: "app:write:save",
780
786
  },
@@ -798,7 +804,7 @@ describe("r.screen() — registration", () => {
798
804
  {
799
805
  kind: "writeForm",
800
806
  title: "s",
801
- fieldDefs: { name: createTextField() },
807
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
802
808
  fields: ["sku"],
803
809
  handler: "app:write:save",
804
810
  },
@@ -825,7 +831,7 @@ describe("r.screen() — registration", () => {
825
831
  {
826
832
  kind: "writeForm",
827
833
  title: "s",
828
- fieldDefs: { name: createTextField() },
834
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
829
835
  fields: ["name"],
830
836
  handler: "app:write:save",
831
837
  },
@@ -849,7 +855,7 @@ describe("r.screen() — registration", () => {
849
855
  {
850
856
  kind: "writeForm",
851
857
  title: "s",
852
- fieldDefs: { name: createTextField() },
858
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
853
859
  fields: ["name"],
854
860
  handler: "app:write:missing",
855
861
  },
@@ -886,7 +892,7 @@ describe("r.screen() — registration", () => {
886
892
  {
887
893
  kind: "writeForm",
888
894
  title: "s",
889
- fieldDefs: { name: createTextField() },
895
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
890
896
  fields: ["name"],
891
897
  handler: "app:write:save",
892
898
  submitLabel: "actions.save",
@@ -928,7 +934,7 @@ describe("r.screen() — registration", () => {
928
934
  {
929
935
  kind: "writeForm",
930
936
  title: "s",
931
- fieldDefs: { name: createTextField() },
937
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
932
938
  fields: ["name"],
933
939
  handler: "app:write:save",
934
940
  },
@@ -970,7 +976,7 @@ describe("r.screen() — registration", () => {
970
976
  {
971
977
  kind: "writeForm",
972
978
  title: "s",
973
- fieldDefs: { name: createTextField() },
979
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
974
980
  fields: ["name"],
975
981
  handler: "app:write:save",
976
982
  },
@@ -996,7 +1002,7 @@ describe("r.screen() — registration", () => {
996
1002
  {
997
1003
  kind: "writeForm",
998
1004
  title: "s",
999
- fieldDefs: { name: createTextField() },
1005
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
1000
1006
  fields: ["name"],
1001
1007
  handler: "shop:write:save",
1002
1008
  },
@@ -1027,7 +1033,7 @@ describe("r.screen() — registration", () => {
1027
1033
  {
1028
1034
  kind: "writeForm",
1029
1035
  title: "s",
1030
- fieldDefs: { name: createTextField() },
1036
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
1031
1037
  fields: ["name"],
1032
1038
  handler: "shop:write:save",
1033
1039
  },
@@ -1060,7 +1066,7 @@ describe("r.screen() — registration", () => {
1060
1066
  {
1061
1067
  kind: "writeForm",
1062
1068
  title: "s",
1063
- fieldDefs: { name: createTextField() },
1069
+ fieldDefs: { name: createTextField({ personal: false, reason: "test_fixture" }) },
1064
1070
  fields: ["name"],
1065
1071
  handler: "shop:write:save",
1066
1072
  },
@@ -124,7 +124,12 @@ describe("buildSearchDocument — contributor precedence (base fields win)", ()
124
124
  const feature = defineFeature("test", (r) => {
125
125
  const thing = r.entity(
126
126
  "thing",
127
- createEntity({ table: "things", fields: { title: createTextField({ searchable: true }) } }),
127
+ createEntity({
128
+ table: "things",
129
+ fields: {
130
+ title: createTextField({ searchable: true, personal: false, reason: "test_fixture" }),
131
+ },
132
+ }),
128
133
  );
129
134
  r.searchPayloadExtension(thing, contributor);
130
135
  });
@@ -151,7 +156,9 @@ describe("buildSearchDocument — contributor precedence (base fields win)", ()
151
156
  "thing-dedup",
152
157
  createEntity({
153
158
  table: "things_dedup",
154
- fields: { title: createTextField({ searchable: true }) },
159
+ fields: {
160
+ title: createTextField({ searchable: true, personal: false, reason: "test_fixture" }),
161
+ },
155
162
  }),
156
163
  );
157
164
  r.searchPayloadExtension(thing, () => ({ title: "from-contributor" }));
@@ -177,7 +184,12 @@ describe("buildSearchDocument — contributor precedence (base fields win)", ()
177
184
  const feature = defineFeature("test", (r) => {
178
185
  const thing = r.entity(
179
186
  "thing",
180
- createEntity({ table: "things", fields: { title: createTextField({ searchable: true }) } }),
187
+ createEntity({
188
+ table: "things",
189
+ fields: {
190
+ title: createTextField({ searchable: true, personal: false, reason: "test_fixture" }),
191
+ },
192
+ }),
181
193
  );
182
194
  r.searchPayloadExtension(thing, () => ({ overlap: "first" }));
183
195
  r.searchPayloadExtension(thing, () => ({ overlap: "second" }));
@@ -65,7 +65,7 @@ describe("r.storeTable — declaration", () => {
65
65
  test("rejects an EntityTableMeta whose source is not 'unmanaged' (#1209)", () => {
66
66
  const managedEntity = createEntity({
67
67
  table: "rt_probe_managed",
68
- fields: { name: createTextField() },
68
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
69
69
  });
70
70
  const managedMeta = deriveEntityTableMeta("rt-probe-managed", managedEntity);
71
71
  expect(() =>
@@ -173,7 +173,10 @@ describe("createRegistry — storeTable aggregation", () => {
173
173
  // default would carry read_, which r.storeTable now rejects outright
174
174
  // (#1220), so the collision case needs a table name storeTable can
175
175
  // actually register.
176
- const widget = createEntity({ table: "shop_widgets", fields: { name: createTextField() } });
176
+ const widget = createEntity({
177
+ table: "shop_widgets",
178
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
179
+ });
177
180
  // resolveTableName mirrors the migrate-runner — pin the exact physical name.
178
181
  const physical = resolveTableName("widget", widget, "shop");
179
182
  const clashing = defineUnmanagedTable({
@@ -203,7 +206,7 @@ describe("createRegistry — store tables with PII-annotated fields (#820)", ()
203
206
  const piiEntity = createEntity({
204
207
  table: "rt_pii_probe",
205
208
  fields: {
206
- userId: createTextField({ required: true }),
209
+ userId: createTextField({ required: true, personal: false, reason: "test_fixture" }),
207
210
  ip: createTextField({
208
211
  personal: { of: "userId" },
209
212
  find: "none",
@@ -52,7 +52,9 @@ describe("validateProjectionAllowlist", () => {
52
52
  "widget",
53
53
  createEntity({
54
54
  table: "widgets",
55
- fields: { label: createTextField({ required: true }) },
55
+ fields: {
56
+ label: createTextField({ required: true, personal: false, reason: "test_fixture" }),
57
+ },
56
58
  }),
57
59
  );
58
60
  });
@@ -97,7 +99,9 @@ describe("validateProjectionAllowlist", () => {
97
99
  "widget",
98
100
  createEntity({
99
101
  table: "widgets-delete",
100
- fields: { label: createTextField({ required: true }) },
102
+ fields: {
103
+ label: createTextField({ required: true, personal: false, reason: "test_fixture" }),
104
+ },
101
105
  }),
102
106
  );
103
107
  });
@@ -353,7 +357,9 @@ describe("validateProjectionAllowlist", () => {
353
357
  "thing",
354
358
  createEntity({
355
359
  table: "shared_table",
356
- fields: { label: createTextField({ required: true }) },
360
+ fields: {
361
+ label: createTextField({ required: true, personal: false, reason: "test_fixture" }),
362
+ },
357
363
  }),
358
364
  );
359
365
  });
@@ -362,7 +368,9 @@ describe("validateProjectionAllowlist", () => {
362
368
  "thing",
363
369
  createEntity({
364
370
  table: "shared_table",
365
- fields: { label: createTextField({ required: true }) },
371
+ fields: {
372
+ label: createTextField({ required: true, personal: false, reason: "test_fixture" }),
373
+ },
366
374
  }),
367
375
  );
368
376
  });
@@ -6,7 +6,13 @@ import { runValidation } from "../validation";
6
6
  describe("validation hooks", () => {
7
7
  test("r.hook registers validation hook", () => {
8
8
  const feature = defineFeature("test", (r) => {
9
- r.entity("user", createEntity({ table: "Users", fields: { email: createTextField() } }));
9
+ r.entity(
10
+ "user",
11
+ createEntity({
12
+ table: "Users",
13
+ fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
14
+ }),
15
+ );
10
16
  r.hook("validation", "user:create", (data) => {
11
17
  const errors: ValidationError[] = [];
12
18
  if (!data["email"]) errors.push({ field: "email", error: "required" });
@@ -32,8 +32,8 @@ function featureWith(entityAccess: AccessMaps, fieldAccess?: AccessMaps): Featur
32
32
  createEntity({
33
33
  table: "fw2626_guard_memos",
34
34
  fields: {
35
- ownerId: createTextField({ required: true }),
36
- title: createTextField({ access: fieldAccess }),
35
+ ownerId: createTextField({ required: true, personal: false, reason: "test_fixture" }),
36
+ title: createTextField({ access: fieldAccess, personal: false, reason: "test_fixture" }),
37
37
  },
38
38
  access: entityAccess,
39
39
  }),
@@ -442,9 +442,9 @@ function deriveField(def: ConfigKeyDefinition): FieldDefinition {
442
442
  case "select":
443
443
  return def.options !== undefined && def.options.length > 0
444
444
  ? createSelectField({ options: def.options })
445
- : createTextField();
445
+ : createTextField({ personal: false, reason: "system_metadata" });
446
446
  default:
447
- return createTextField();
447
+ return createTextField({ personal: false, reason: "system_metadata" });
448
448
  }
449
449
  }
450
450
 
@@ -43,7 +43,7 @@ import { runPendingSeedMigrations } from "../runner";
43
43
  // is exercised against the production write-pipeline, not a stubbed return.
44
44
  const probeEntity = createEntity({
45
45
  table: "read_esops_probes",
46
- fields: { label: createTextField({ required: true }) },
46
+ fields: { label: createTextField({ personal: false, reason: "test_fixture", required: true }) },
47
47
  });
48
48
  const probeTable = buildEntityTable("esops-probe", probeEntity);
49
49
  const probeExecutor = createEventStoreExecutor(probeTable, probeEntity, {
@@ -33,7 +33,7 @@ import { upcastStoredEvent } from "../upcaster";
33
33
  const orderEntity = createEntity({
34
34
  table: "read_upcast_orders",
35
35
  fields: {
36
- customer: createTextField({ required: true }),
36
+ customer: createTextField({ personal: false, reason: "test_fixture", required: true }),
37
37
  },
38
38
  });
39
39
  const orderTable = buildEntityTable("upcast-order", orderEntity);
@@ -47,7 +47,7 @@ import { createLocalProvider } from "../local-provider";
47
47
  const documentEntity = createEntity({
48
48
  table: "pipeline_documents",
49
49
  fields: {
50
- title: createTextField({ required: true }),
50
+ title: createTextField({ personal: false, reason: "test_fixture", required: true }),
51
51
  attachment: createFileField(),
52
52
  cover: createImageField(),
53
53
  photos: createImagesField(),
@@ -57,7 +57,7 @@ const JWT_SECRET = "files-test-secret-at-least-32-characters!!";
57
57
  const testTenantEntity = createEntity({
58
58
  table: "test_tenants",
59
59
  fields: {
60
- name: createTextField({ required: true }),
60
+ name: createTextField({ personal: false, reason: "test_fixture", required: true }),
61
61
  logo: createImageField({ maxSize: "2mb", accept: ["png", "jpg"] }),
62
62
  },
63
63
  });
@@ -14,20 +14,20 @@ import { createBigIntField, createEntity, createTextField } from "../engine";
14
14
  // ohne `.default(now()).notNull()` macht inserted_at still nullable.
15
15
  //
16
16
  // PII-Annotations:
17
- // - fileName → personal: "self" (Originalname enthält oft Personen-Bezug:
18
- // "Marc-Lebenslauf.pdf", "Krankheitsattest-Mai.pdf"). Andere Felder
19
- // (storageKey, mimeType, size, entityType, entityId, fieldName) treffen
20
- // die PII-Heuristik nicht.
17
+ // - fileName → personal: "self" (original filename often carries a personal
18
+ // reference: "Marc-Lebenslauf.pdf", "Krankheitsattest-Mai.pdf"). The other
19
+ // fields (storageKey, mimeType, entityType, entityId, fieldName) are
20
+ // technical references or system metadata, not subject content.
21
21
  export const fileRefEntity = createEntity({
22
22
  table: "file_refs",
23
23
  softDelete: true,
24
24
  fields: {
25
- storageKey: createTextField({ required: true }),
25
+ storageKey: createTextField({ required: true, personal: false, reason: "technical_reference" }),
26
26
  fileName: createTextField({ required: true, personal: "self", find: "none" }),
27
- mimeType: createTextField({ required: true }),
27
+ mimeType: createTextField({ required: true, personal: false, reason: "system_metadata" }),
28
28
  size: createBigIntField({ required: true }),
29
- entityType: createTextField(),
30
- entityId: createTextField(),
31
- fieldName: createTextField(),
29
+ entityType: createTextField({ personal: false, reason: "technical_reference" }),
30
+ entityId: createTextField({ personal: false, reason: "technical_reference" }),
31
+ fieldName: createTextField({ personal: false, reason: "technical_reference" }),
32
32
  },
33
33
  });
@@ -4,7 +4,13 @@ import { createI18n } from "../index";
4
4
 
5
5
  describe("createI18n", () => {
6
6
  const adminFeature = defineFeature("adminUsers", (r) => {
7
- r.entity("user", createEntity({ table: "Users", fields: { email: createTextField() } }));
7
+ r.entity(
8
+ "user",
9
+ createEntity({
10
+ table: "Users",
11
+ fields: { email: createTextField({ personal: false, reason: "test_fixture" }) },
12
+ }),
13
+ );
8
14
  r.translations({
9
15
  keys: {
10
16
  "nav.title": { de: "Benutzer", en: "Users" },
@@ -198,7 +198,9 @@ describe("kumiko-drift end-to-end (generate → apply → gate)", () => {
198
198
  test("generate from entity metas → apply → gate ok (the local-verify proof)", async () => {
199
199
  const entity = createEntity({
200
200
  table: "kdrift_gen",
201
- fields: { name: createTextField({ required: true }) },
201
+ fields: {
202
+ name: createTextField({ personal: false, reason: "test_fixture", required: true }),
203
+ },
202
204
  });
203
205
  const meta = deriveEntityTableMeta("kdriftGen", entity);
204
206
  const result = generateMigration({
@@ -43,8 +43,8 @@ import {
43
43
  const itemEntity = createEntity({
44
44
  table: "read_pending_items",
45
45
  fields: {
46
- groupId: createTextField({ required: true }),
47
- name: createTextField({ required: true }),
46
+ groupId: createTextField({ personal: false, reason: "test_fixture", required: true }),
47
+ name: createTextField({ personal: false, reason: "test_fixture", required: true }),
48
48
  },
49
49
  });
50
50
  const itemTable = buildEntityTable("pending-item", itemEntity);
@@ -25,7 +25,7 @@ import {
25
25
 
26
26
  const itemEntity = createEntity({
27
27
  table: "read_arch_items",
28
- fields: { label: createTextField({ required: true }) },
28
+ fields: { label: createTextField({ personal: false, reason: "test_fixture", required: true }) },
29
29
  });
30
30
  const itemTable = buildEntityTable("arch-item", itemEntity);
31
31
 
@@ -43,39 +43,54 @@ const admin = TestUsers.admin;
43
43
 
44
44
  const departmentEntity = createEntity({
45
45
  table: "cascade_departments",
46
- fields: { name: createTextField() },
46
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
47
47
  });
48
48
  const userEntity = createEntity({
49
49
  table: "cascade_users",
50
- fields: { name: createTextField(), departmentId: createTextField() },
50
+ fields: {
51
+ name: createTextField({ personal: false, reason: "test_fixture" }),
52
+ departmentId: createTextField({ personal: false, reason: "test_fixture" }),
53
+ },
51
54
  });
52
55
  const sessionEntity = createEntity({
53
56
  table: "cascade_sessions",
54
- fields: { userId: createTextField(), token: createTextField() },
57
+ fields: {
58
+ userId: createTextField({ personal: false, reason: "test_fixture" }),
59
+ token: createTextField({ personal: false, reason: "test_fixture" }),
60
+ },
55
61
  });
56
62
  const groupEntity = createEntity({
57
63
  table: "cascade_groups",
58
- fields: { name: createTextField() },
64
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
59
65
  });
60
66
  // Two separate junction tables so one Registry can host both onDelete
61
67
  // strategies (restrict + cascade) on the same user→group pair.
62
68
  const userGroupRestrictEntity = createEntity({
63
69
  table: "cascade_user_group_restrict",
64
- fields: { userId: createTextField(), groupId: createTextField() },
70
+ fields: {
71
+ userId: createTextField({ personal: false, reason: "test_fixture" }),
72
+ groupId: createTextField({ personal: false, reason: "test_fixture" }),
73
+ },
65
74
  });
66
75
  const userGroupCascadeEntity = createEntity({
67
76
  table: "cascade_user_group_cascade",
68
- fields: { userId: createTextField(), groupId: createTextField() },
77
+ fields: {
78
+ userId: createTextField({ personal: false, reason: "test_fixture" }),
79
+ groupId: createTextField({ personal: false, reason: "test_fixture" }),
80
+ },
69
81
  });
70
82
  // setNull pair: team→member with onDelete "setNull" — members survive
71
83
  // the team deletion with teamId nulled out.
72
84
  const teamEntity = createEntity({
73
85
  table: "cascade_teams",
74
- fields: { name: createTextField() },
86
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
75
87
  });
76
88
  const memberEntity = createEntity({
77
89
  table: "cascade_members",
78
- fields: { name: createTextField(), teamId: createTextField() },
90
+ fields: {
91
+ name: createTextField({ personal: false, reason: "test_fixture" }),
92
+ teamId: createTextField({ personal: false, reason: "test_fixture" }),
93
+ },
79
94
  });
80
95
 
81
96
  beforeAll(async () => {
@@ -5,10 +5,25 @@ describe("getIncomingRelations", () => {
5
5
  const feature = defineFeature("core", (r) => {
6
6
  r.entity(
7
7
  "department",
8
- createEntity({ table: "Departments", fields: { name: createTextField() } }),
8
+ createEntity({
9
+ table: "Departments",
10
+ fields: { name: createTextField({ personal: false, reason: "test_fixture" }) },
11
+ }),
12
+ );
13
+ r.entity(
14
+ "user",
15
+ createEntity({
16
+ table: "Users",
17
+ fields: { departmentId: createTextField({ personal: false, reason: "test_fixture" }) },
18
+ }),
19
+ );
20
+ r.entity(
21
+ "session",
22
+ createEntity({
23
+ table: "Sessions",
24
+ fields: { userId: createTextField({ personal: false, reason: "test_fixture" }) },
25
+ }),
9
26
  );
10
- r.entity("user", createEntity({ table: "Users", fields: { departmentId: createTextField() } }));
11
- r.entity("session", createEntity({ table: "Sessions", fields: { userId: createTextField() } }));
12
27
 
13
28
  r.relation("department", "users", {
14
29
  type: "hasMany",
@@ -36,7 +36,7 @@ import {
36
36
  const orderEntity = createEntity({
37
37
  table: "read_causation_orders",
38
38
  fields: {
39
- item: createTextField({ required: true }),
39
+ item: createTextField({ personal: false, reason: "test_fixture", required: true }),
40
40
  },
41
41
  });
42
42