@happyvertical/smrt-education 0.57.37 → 0.57.38

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 (47) hide show
  1. package/AGENTS.md +4 -0
  2. package/agents/family-intake.md +97 -0
  3. package/dist/catalog.d.ts +4 -4
  4. package/dist/catalog.d.ts.map +1 -1
  5. package/dist/chunks/{workbook-photo-service-1wcnf-Xf.js → workbook-photo-service-DCmqeWLd.js} +448 -202
  6. package/dist/chunks/workbook-photo-service-DCmqeWLd.js.map +1 -0
  7. package/dist/course-source.d.ts +2 -2
  8. package/dist/course-source.d.ts.map +1 -1
  9. package/dist/family-intake-contracts.d.ts +56 -0
  10. package/dist/family-intake-contracts.d.ts.map +1 -0
  11. package/dist/family-intake-ingestion.d.ts +29 -0
  12. package/dist/family-intake-ingestion.d.ts.map +1 -0
  13. package/dist/family-intake-models.d.ts +58 -0
  14. package/dist/family-intake-models.d.ts.map +1 -0
  15. package/dist/family-intake-service.d.ts +70 -0
  16. package/dist/family-intake-service.d.ts.map +1 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +5 -5
  20. package/dist/index.js.map +1 -1
  21. package/dist/ingestion.d.ts +2 -0
  22. package/dist/ingestion.d.ts.map +1 -1
  23. package/dist/ingestion.js +426 -13
  24. package/dist/ingestion.js.map +1 -1
  25. package/dist/intake-original-evidence.d.ts +10 -0
  26. package/dist/intake-original-evidence.d.ts.map +1 -0
  27. package/dist/learner-service.d.ts +2 -0
  28. package/dist/learner-service.d.ts.map +1 -1
  29. package/dist/learners.d.ts +5 -5
  30. package/dist/learners.d.ts.map +1 -1
  31. package/dist/lesson-assets.d.ts +2 -2
  32. package/dist/lesson-assets.d.ts.map +1 -1
  33. package/dist/manifest.json +1319 -78
  34. package/dist/smrt-knowledge.json +524 -10
  35. package/dist/submission-service.d.ts +1 -1
  36. package/dist/submission-service.d.ts.map +1 -1
  37. package/dist/submissions.d.ts +7 -7
  38. package/dist/submissions.d.ts.map +1 -1
  39. package/dist/workbook-models.d.ts +8 -8
  40. package/dist/workbook-models.d.ts.map +1 -1
  41. package/dist/workbook-photo-ingestion.d.ts.map +1 -1
  42. package/dist/workbook-photo-models.d.ts +6 -5
  43. package/dist/workbook-photo-models.d.ts.map +1 -1
  44. package/dist/workbook-photo-service.d.ts +6 -0
  45. package/dist/workbook-photo-service.d.ts.map +1 -1
  46. package/package.json +8 -8
  47. package/dist/chunks/workbook-photo-service-1wcnf-Xf.js.map +0 -1
@@ -3,18 +3,19 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-education",
6
- "packageVersion": "0.57.37",
6
+ "packageVersion": "0.57.38",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "13a3f757f18cc0cfed8d07ffc42cda60e62cf40766265cc23d08ed0482704806",
11
- "packageJson": "8707ae756fce4cae2c1ad80e92b1352ecd85386f1b7f6b58c925cfba44e5d19b",
12
- "agents": "bf8b00b31d2dfc9394ab1766421bbeb2dcc5326db3ea60ecc9922b6800f21f48",
10
+ "manifest": "f63db1cd3e8bf488aa731aed6f5b4cb1ff6791a221b9bac788a2a6ce223abe1c",
11
+ "packageJson": "5075accbaa27c88f5eff6b23f3462dcb8ddd4c50b862775a1720809f73cfe2c1",
12
+ "agents": "dd188ff6cfca738bf1dcc08ef4e86c8870c8add515092d971c9a2befd3568942",
13
13
  "moduleDoc:agents/learner-service.md": "7da70d214547eb78fbf058e997599cc80ab86f5bb55748bd158a9a4b30070d3b",
14
14
  "moduleDoc:agents/submission-service.md": "8e63b83ac84628d5e5ddacbb6a47077c0e65eee3da87518d9bf6e30fb8348336",
15
15
  "moduleDoc:agents/workbook-service.md": "3ca3fb60d39daf76b94ec668fc19dc67aa7e090b7f44412bed5c9d92e8efaf5a",
16
16
  "moduleDoc:agents/photo-intake.md": "3b7057201ee30b2361aad23ea52e8a55c8ed5354e7a7e4a8193b7de17ca2f0db",
17
- "moduleDoc:agents/source-import.md": "30ee823589d655442bcf1abcd86a2132172065b4bc5e3c4d89b1e8b7afcc66bc"
17
+ "moduleDoc:agents/source-import.md": "30ee823589d655442bcf1abcd86a2132172065b4bc5e3c4d89b1e8b7afcc66bc",
18
+ "moduleDoc:agents/family-intake.md": "540b6d37f438496acb0208b6ac7258264e2142bce3d2f986967b7741606fe4f7"
18
19
  },
19
20
  "exports": [
20
21
  ".",
@@ -59,7 +60,7 @@
59
60
  "smrt"
60
61
  ],
61
62
  "risks": [
62
- "cross-package-refs:6",
63
+ "cross-package-refs:8",
63
64
  "sensitive-fields-excluded",
64
65
  "sti-inheritance"
65
66
  ],
@@ -741,6 +742,9 @@
741
742
  {
742
743
  "name": "save",
743
744
  "async": true,
745
+ "params": [
746
+ "options?: SmrtSaveOptions"
747
+ ],
744
748
  "returns": "Promise<this>"
745
749
  }
746
750
  ],
@@ -923,6 +927,9 @@
923
927
  {
924
928
  "name": "save",
925
929
  "async": true,
930
+ "params": [
931
+ "options?: SmrtSaveOptions"
932
+ ],
926
933
  "returns": "Promise<this>"
927
934
  }
928
935
  ],
@@ -1094,6 +1101,9 @@
1094
1101
  {
1095
1102
  "name": "save",
1096
1103
  "async": true,
1104
+ "params": [
1105
+ "options?: SmrtSaveOptions"
1106
+ ],
1097
1107
  "returns": "Promise<this>"
1098
1108
  }
1099
1109
  ],
@@ -1166,6 +1176,9 @@
1166
1176
  {
1167
1177
  "name": "save",
1168
1178
  "async": true,
1179
+ "params": [
1180
+ "options?: SmrtSaveOptions"
1181
+ ],
1169
1182
  "returns": "Promise<this>"
1170
1183
  }
1171
1184
  ],
@@ -1306,6 +1319,9 @@
1306
1319
  {
1307
1320
  "name": "save",
1308
1321
  "async": true,
1322
+ "params": [
1323
+ "options?: SmrtSaveOptions"
1324
+ ],
1309
1325
  "returns": "Promise<this>"
1310
1326
  }
1311
1327
  ],
@@ -1448,6 +1464,9 @@
1448
1464
  {
1449
1465
  "name": "save",
1450
1466
  "async": true,
1467
+ "params": [
1468
+ "options?: SmrtSaveOptions"
1469
+ ],
1451
1470
  "returns": "Promise<this>"
1452
1471
  }
1453
1472
  ],
@@ -1585,6 +1604,9 @@
1585
1604
  {
1586
1605
  "name": "save",
1587
1606
  "async": true,
1607
+ "params": [
1608
+ "options?: SmrtSaveOptions"
1609
+ ],
1588
1610
  "returns": "Promise<this>"
1589
1611
  }
1590
1612
  ],
@@ -1735,6 +1757,9 @@
1735
1757
  {
1736
1758
  "name": "save",
1737
1759
  "async": true,
1760
+ "params": [
1761
+ "options?: SmrtSaveOptions"
1762
+ ],
1738
1763
  "returns": "Promise<this>"
1739
1764
  }
1740
1765
  ],
@@ -1866,6 +1891,9 @@
1866
1891
  {
1867
1892
  "name": "save",
1868
1893
  "async": true,
1894
+ "params": [
1895
+ "options?: SmrtSaveOptions"
1896
+ ],
1869
1897
  "returns": "Promise<this>"
1870
1898
  }
1871
1899
  ],
@@ -2501,6 +2529,9 @@
2501
2529
  {
2502
2530
  "name": "save",
2503
2531
  "async": true,
2532
+ "params": [
2533
+ "options?: SmrtSaveOptions"
2534
+ ],
2504
2535
  "returns": "Promise<this>"
2505
2536
  },
2506
2537
  {
@@ -2568,6 +2599,401 @@
2568
2599
  "tags": [],
2569
2600
  "risks": []
2570
2601
  },
2602
+ {
2603
+ "name": "FamilyIntake",
2604
+ "qualifiedName": "@happyvertical/smrt-education:FamilyIntake",
2605
+ "collection": "familyintakes",
2606
+ "description": "Family-owned receipt, independent of learner attribution and ingestion expiry.",
2607
+ "tableName": "family_intakes",
2608
+ "packageName": "@happyvertical/smrt-education",
2609
+ "extends": "SmrtObject",
2610
+ "fields": [
2611
+ {
2612
+ "name": "tenantId",
2613
+ "type": "text",
2614
+ "required": true,
2615
+ "columnType": "UUID"
2616
+ },
2617
+ {
2618
+ "name": "itemId",
2619
+ "type": "text",
2620
+ "required": false,
2621
+ "columnType": "TEXT"
2622
+ },
2623
+ {
2624
+ "name": "actorUserId",
2625
+ "type": "text",
2626
+ "required": false,
2627
+ "columnType": "TEXT"
2628
+ },
2629
+ {
2630
+ "name": "ownerProfileId",
2631
+ "type": "crossPackageRef",
2632
+ "required": false,
2633
+ "related": "@happyvertical/smrt-profiles:Profile",
2634
+ "columnType": "UUID"
2635
+ },
2636
+ {
2637
+ "name": "contentDigest",
2638
+ "type": "text",
2639
+ "required": false,
2640
+ "columnType": "TEXT"
2641
+ },
2642
+ {
2643
+ "name": "sourceJson",
2644
+ "type": "text",
2645
+ "required": false,
2646
+ "columnType": "TEXT"
2647
+ }
2648
+ ],
2649
+ "relationships": [
2650
+ {
2651
+ "name": "ownerProfileId",
2652
+ "type": "crossPackageRef",
2653
+ "required": false,
2654
+ "related": "@happyvertical/smrt-profiles:Profile",
2655
+ "columnType": "UUID"
2656
+ }
2657
+ ],
2658
+ "methods": [
2659
+ "delete",
2660
+ "save"
2661
+ ],
2662
+ "methodSignatures": [
2663
+ {
2664
+ "name": "delete",
2665
+ "async": true,
2666
+ "returns": "Promise<void>"
2667
+ },
2668
+ {
2669
+ "name": "save",
2670
+ "async": true,
2671
+ "params": [
2672
+ "options?: SmrtSaveOptions"
2673
+ ],
2674
+ "returns": "Promise<this>"
2675
+ }
2676
+ ],
2677
+ "tenant": {
2678
+ "scoped": true,
2679
+ "mode": "required",
2680
+ "field": "tenantId"
2681
+ },
2682
+ "conflictColumns": [
2683
+ "tenant_id",
2684
+ "item_id"
2685
+ ],
2686
+ "surfaces": [],
2687
+ "withheldSurfaces": [
2688
+ {
2689
+ "kind": "api",
2690
+ "operation": "delete",
2691
+ "code": "api-disabled",
2692
+ "reason": "api is disabled",
2693
+ "objectName": "@happyvertical/smrt-education:FamilyIntake"
2694
+ },
2695
+ {
2696
+ "kind": "api",
2697
+ "operation": "save",
2698
+ "code": "api-disabled",
2699
+ "reason": "api is disabled",
2700
+ "objectName": "@happyvertical/smrt-education:FamilyIntake"
2701
+ }
2702
+ ],
2703
+ "relationshipFeatures": [
2704
+ "crossPackageRef",
2705
+ "uuidColumns"
2706
+ ],
2707
+ "tags": [],
2708
+ "risks": []
2709
+ },
2710
+ {
2711
+ "name": "FamilyIntakeCollection",
2712
+ "qualifiedName": "@happyvertical/smrt-education:FamilyIntakeCollection",
2713
+ "collection": "familyintakes",
2714
+ "tableName": "family_intakes",
2715
+ "packageName": "@happyvertical/smrt-education",
2716
+ "extends": "SmrtCollection",
2717
+ "fields": [],
2718
+ "relationships": [],
2719
+ "methods": [],
2720
+ "surfaces": [],
2721
+ "relationshipFeatures": [
2722
+ "uuidColumns"
2723
+ ],
2724
+ "tags": [],
2725
+ "risks": []
2726
+ },
2727
+ {
2728
+ "name": "FamilyIntakeAsset",
2729
+ "qualifiedName": "@happyvertical/smrt-education:FamilyIntakeAsset",
2730
+ "displayLabelField": "name",
2731
+ "collection": "familyintakeassets",
2732
+ "description": "Sole family owner join; adoption borrows this exact immutable original.",
2733
+ "tableName": "family_intake_assets",
2734
+ "packageName": "@happyvertical/smrt-education",
2735
+ "extends": "SmrtObject",
2736
+ "fields": [
2737
+ {
2738
+ "name": "tenantId",
2739
+ "type": "text",
2740
+ "required": true,
2741
+ "columnType": "UUID"
2742
+ },
2743
+ {
2744
+ "name": "intakeId",
2745
+ "type": "foreignKey",
2746
+ "required": true,
2747
+ "related": "FamilyIntake",
2748
+ "columnType": "UUID"
2749
+ },
2750
+ {
2751
+ "name": "assetId",
2752
+ "type": "crossPackageRef",
2753
+ "required": false,
2754
+ "related": "@happyvertical/smrt-assets:Asset",
2755
+ "columnType": "UUID"
2756
+ },
2757
+ {
2758
+ "name": "name",
2759
+ "type": "text",
2760
+ "required": false,
2761
+ "columnType": "TEXT"
2762
+ },
2763
+ {
2764
+ "name": "mimeType",
2765
+ "type": "text",
2766
+ "required": false,
2767
+ "columnType": "TEXT"
2768
+ },
2769
+ {
2770
+ "name": "sha256",
2771
+ "type": "text",
2772
+ "required": false,
2773
+ "columnType": "TEXT"
2774
+ },
2775
+ {
2776
+ "name": "position",
2777
+ "type": "integer",
2778
+ "required": true,
2779
+ "columnType": "INTEGER",
2780
+ "default": 0
2781
+ }
2782
+ ],
2783
+ "relationships": [
2784
+ {
2785
+ "name": "intakeId",
2786
+ "type": "foreignKey",
2787
+ "required": true,
2788
+ "related": "FamilyIntake",
2789
+ "columnType": "UUID"
2790
+ },
2791
+ {
2792
+ "name": "assetId",
2793
+ "type": "crossPackageRef",
2794
+ "required": false,
2795
+ "related": "@happyvertical/smrt-assets:Asset",
2796
+ "columnType": "UUID"
2797
+ }
2798
+ ],
2799
+ "methods": [
2800
+ "delete",
2801
+ "save"
2802
+ ],
2803
+ "methodSignatures": [
2804
+ {
2805
+ "name": "delete",
2806
+ "async": true,
2807
+ "returns": "Promise<void>"
2808
+ },
2809
+ {
2810
+ "name": "save",
2811
+ "async": true,
2812
+ "params": [
2813
+ "options?: SmrtSaveOptions"
2814
+ ],
2815
+ "returns": "Promise<this>"
2816
+ }
2817
+ ],
2818
+ "tenant": {
2819
+ "scoped": true,
2820
+ "mode": "required",
2821
+ "field": "tenantId"
2822
+ },
2823
+ "conflictColumns": [
2824
+ "tenant_id",
2825
+ "intake_id",
2826
+ "asset_id"
2827
+ ],
2828
+ "surfaces": [],
2829
+ "withheldSurfaces": [
2830
+ {
2831
+ "kind": "api",
2832
+ "operation": "delete",
2833
+ "code": "api-disabled",
2834
+ "reason": "api is disabled",
2835
+ "objectName": "@happyvertical/smrt-education:FamilyIntakeAsset"
2836
+ },
2837
+ {
2838
+ "kind": "api",
2839
+ "operation": "save",
2840
+ "code": "api-disabled",
2841
+ "reason": "api is disabled",
2842
+ "objectName": "@happyvertical/smrt-education:FamilyIntakeAsset"
2843
+ }
2844
+ ],
2845
+ "relationshipFeatures": [
2846
+ "crossPackageRef",
2847
+ "foreignKey",
2848
+ "uuidColumns"
2849
+ ],
2850
+ "tags": [],
2851
+ "risks": []
2852
+ },
2853
+ {
2854
+ "name": "FamilyIntakeAssetCollection",
2855
+ "qualifiedName": "@happyvertical/smrt-education:FamilyIntakeAssetCollection",
2856
+ "collection": "familyintakeassets",
2857
+ "tableName": "family_intake_assets",
2858
+ "packageName": "@happyvertical/smrt-education",
2859
+ "extends": "SmrtCollection",
2860
+ "fields": [],
2861
+ "relationships": [],
2862
+ "methods": [],
2863
+ "surfaces": [],
2864
+ "relationshipFeatures": [
2865
+ "uuidColumns"
2866
+ ],
2867
+ "tags": [],
2868
+ "risks": []
2869
+ },
2870
+ {
2871
+ "name": "FamilyIntakeDecision",
2872
+ "qualifiedName": "@happyvertical/smrt-education:FamilyIntakeDecision",
2873
+ "collection": "familyintakedecisions",
2874
+ "description": "Append-only attribution/adoption audit; no marks or learning outcomes.",
2875
+ "tableName": "family_intake_decisions",
2876
+ "packageName": "@happyvertical/smrt-education",
2877
+ "extends": "SmrtObject",
2878
+ "fields": [
2879
+ {
2880
+ "name": "tenantId",
2881
+ "type": "text",
2882
+ "required": true,
2883
+ "columnType": "UUID"
2884
+ },
2885
+ {
2886
+ "name": "intakeId",
2887
+ "type": "foreignKey",
2888
+ "required": true,
2889
+ "related": "FamilyIntake",
2890
+ "columnType": "UUID"
2891
+ },
2892
+ {
2893
+ "name": "requestKey",
2894
+ "type": "text",
2895
+ "required": false,
2896
+ "columnType": "TEXT"
2897
+ },
2898
+ {
2899
+ "name": "sequence",
2900
+ "type": "integer",
2901
+ "required": true,
2902
+ "columnType": "INTEGER",
2903
+ "default": 0
2904
+ },
2905
+ {
2906
+ "name": "actorUserId",
2907
+ "type": "text",
2908
+ "required": false,
2909
+ "columnType": "TEXT"
2910
+ },
2911
+ {
2912
+ "name": "bodyJson",
2913
+ "type": "text",
2914
+ "required": false,
2915
+ "columnType": "TEXT"
2916
+ }
2917
+ ],
2918
+ "relationships": [
2919
+ {
2920
+ "name": "intakeId",
2921
+ "type": "foreignKey",
2922
+ "required": true,
2923
+ "related": "FamilyIntake",
2924
+ "columnType": "UUID"
2925
+ }
2926
+ ],
2927
+ "methods": [
2928
+ "delete",
2929
+ "save"
2930
+ ],
2931
+ "methodSignatures": [
2932
+ {
2933
+ "name": "delete",
2934
+ "async": true,
2935
+ "returns": "Promise<void>"
2936
+ },
2937
+ {
2938
+ "name": "save",
2939
+ "async": true,
2940
+ "params": [
2941
+ "options?: SmrtSaveOptions"
2942
+ ],
2943
+ "returns": "Promise<this>"
2944
+ }
2945
+ ],
2946
+ "tenant": {
2947
+ "scoped": true,
2948
+ "mode": "required",
2949
+ "field": "tenantId"
2950
+ },
2951
+ "conflictColumns": [
2952
+ "tenant_id",
2953
+ "intake_id",
2954
+ "request_key"
2955
+ ],
2956
+ "surfaces": [],
2957
+ "withheldSurfaces": [
2958
+ {
2959
+ "kind": "api",
2960
+ "operation": "delete",
2961
+ "code": "api-disabled",
2962
+ "reason": "api is disabled",
2963
+ "objectName": "@happyvertical/smrt-education:FamilyIntakeDecision"
2964
+ },
2965
+ {
2966
+ "kind": "api",
2967
+ "operation": "save",
2968
+ "code": "api-disabled",
2969
+ "reason": "api is disabled",
2970
+ "objectName": "@happyvertical/smrt-education:FamilyIntakeDecision"
2971
+ }
2972
+ ],
2973
+ "relationshipFeatures": [
2974
+ "foreignKey",
2975
+ "uuidColumns"
2976
+ ],
2977
+ "tags": [],
2978
+ "risks": []
2979
+ },
2980
+ {
2981
+ "name": "FamilyIntakeDecisionCollection",
2982
+ "qualifiedName": "@happyvertical/smrt-education:FamilyIntakeDecisionCollection",
2983
+ "collection": "familyintakedecisions",
2984
+ "tableName": "family_intake_decisions",
2985
+ "packageName": "@happyvertical/smrt-education",
2986
+ "extends": "SmrtCollection",
2987
+ "fields": [],
2988
+ "relationships": [],
2989
+ "methods": [],
2990
+ "surfaces": [],
2991
+ "relationshipFeatures": [
2992
+ "uuidColumns"
2993
+ ],
2994
+ "tags": [],
2995
+ "risks": []
2996
+ },
2571
2997
  {
2572
2998
  "name": "Learner",
2573
2999
  "qualifiedName": "@happyvertical/smrt-education:Learner",
@@ -2652,6 +3078,9 @@
2652
3078
  {
2653
3079
  "name": "save",
2654
3080
  "async": true,
3081
+ "params": [
3082
+ "options?: SmrtSaveOptions"
3083
+ ],
2655
3084
  "returns": "Promise<this>"
2656
3085
  },
2657
3086
  {
@@ -2768,6 +3197,9 @@
2768
3197
  {
2769
3198
  "name": "save",
2770
3199
  "async": true,
3200
+ "params": [
3201
+ "options?: SmrtSaveOptions"
3202
+ ],
2771
3203
  "returns": "Promise<this>"
2772
3204
  }
2773
3205
  ],
@@ -2898,6 +3330,9 @@
2898
3330
  {
2899
3331
  "name": "save",
2900
3332
  "async": true,
3333
+ "params": [
3334
+ "options?: SmrtSaveOptions"
3335
+ ],
2901
3336
  "returns": "Promise<this>"
2902
3337
  }
2903
3338
  ],
@@ -3034,6 +3469,9 @@
3034
3469
  {
3035
3470
  "name": "save",
3036
3471
  "async": true,
3472
+ "params": [
3473
+ "options?: SmrtSaveOptions"
3474
+ ],
3037
3475
  "returns": "Promise<this>"
3038
3476
  }
3039
3477
  ],
@@ -3130,6 +3568,9 @@
3130
3568
  {
3131
3569
  "name": "save",
3132
3570
  "async": true,
3571
+ "params": [
3572
+ "options?: SmrtSaveOptions"
3573
+ ],
3133
3574
  "returns": "Promise<this>"
3134
3575
  }
3135
3576
  ],
@@ -3299,6 +3740,9 @@
3299
3740
  {
3300
3741
  "name": "save",
3301
3742
  "async": true,
3743
+ "params": [
3744
+ "options?: SmrtSaveOptions"
3745
+ ],
3302
3746
  "returns": "Promise<this>"
3303
3747
  }
3304
3748
  ],
@@ -3376,6 +3820,9 @@
3376
3820
  {
3377
3821
  "name": "save",
3378
3822
  "async": true,
3823
+ "params": [
3824
+ "options?: SmrtSaveOptions"
3825
+ ],
3379
3826
  "returns": "Promise<this>"
3380
3827
  }
3381
3828
  ],
@@ -3567,6 +4014,9 @@
3567
4014
  {
3568
4015
  "name": "save",
3569
4016
  "async": true,
4017
+ "params": [
4018
+ "options?: SmrtSaveOptions"
4019
+ ],
3570
4020
  "returns": "Promise<this>"
3571
4021
  },
3572
4022
  {
@@ -3765,6 +4215,9 @@
3765
4215
  {
3766
4216
  "name": "save",
3767
4217
  "async": true,
4218
+ "params": [
4219
+ "options?: SmrtSaveOptions"
4220
+ ],
3768
4221
  "returns": "Promise<this>"
3769
4222
  }
3770
4223
  ],
@@ -3923,6 +4376,9 @@
3923
4376
  {
3924
4377
  "name": "save",
3925
4378
  "async": true,
4379
+ "params": [
4380
+ "options?: SmrtSaveOptions"
4381
+ ],
3926
4382
  "returns": "Promise<this>"
3927
4383
  }
3928
4384
  ],
@@ -4011,6 +4467,9 @@
4011
4467
  {
4012
4468
  "name": "save",
4013
4469
  "async": true,
4470
+ "params": [
4471
+ "options?: SmrtSaveOptions"
4472
+ ],
4014
4473
  "returns": "Promise<this>"
4015
4474
  }
4016
4475
  ],
@@ -4145,6 +4604,9 @@
4145
4604
  {
4146
4605
  "name": "save",
4147
4606
  "async": true,
4607
+ "params": [
4608
+ "options?: SmrtSaveOptions"
4609
+ ],
4148
4610
  "returns": "Promise<this>"
4149
4611
  },
4150
4612
  {
@@ -4269,6 +4731,9 @@
4269
4731
  {
4270
4732
  "name": "save",
4271
4733
  "async": true,
4734
+ "params": [
4735
+ "options?: SmrtSaveOptions"
4736
+ ],
4272
4737
  "returns": "Promise<this>"
4273
4738
  }
4274
4739
  ],
@@ -4436,6 +4901,9 @@
4436
4901
  {
4437
4902
  "name": "save",
4438
4903
  "async": true,
4904
+ "params": [
4905
+ "options?: SmrtSaveOptions"
4906
+ ],
4439
4907
  "returns": "Promise<this>"
4440
4908
  }
4441
4909
  ],
@@ -4615,6 +5083,9 @@
4615
5083
  {
4616
5084
  "name": "save",
4617
5085
  "async": true,
5086
+ "params": [
5087
+ "options?: SmrtSaveOptions"
5088
+ ],
4618
5089
  "returns": "Promise<this>"
4619
5090
  }
4620
5091
  ],
@@ -4800,6 +5271,9 @@
4800
5271
  {
4801
5272
  "name": "save",
4802
5273
  "async": true,
5274
+ "params": [
5275
+ "options?: SmrtSaveOptions"
5276
+ ],
4803
5277
  "returns": "Promise<this>"
4804
5278
  }
4805
5279
  ],
@@ -4982,6 +5456,9 @@
4982
5456
  {
4983
5457
  "name": "save",
4984
5458
  "async": true,
5459
+ "params": [
5460
+ "options?: SmrtSaveOptions"
5461
+ ],
4985
5462
  "returns": "Promise<this>"
4986
5463
  }
4987
5464
  ],
@@ -5141,6 +5618,9 @@
5141
5618
  {
5142
5619
  "name": "save",
5143
5620
  "async": true,
5621
+ "params": [
5622
+ "options?: SmrtSaveOptions"
5623
+ ],
5144
5624
  "returns": "Promise<this>"
5145
5625
  }
5146
5626
  ],
@@ -5286,6 +5766,9 @@
5286
5766
  {
5287
5767
  "name": "save",
5288
5768
  "async": true,
5769
+ "params": [
5770
+ "options?: SmrtSaveOptions"
5771
+ ],
5289
5772
  "returns": "Promise<this>"
5290
5773
  }
5291
5774
  ],
@@ -5363,6 +5846,13 @@
5363
5846
  "related": "Learner",
5364
5847
  "columnType": "UUID"
5365
5848
  },
5849
+ {
5850
+ "name": "familyIntakeId",
5851
+ "type": "foreignKey",
5852
+ "required": false,
5853
+ "related": "FamilyIntake",
5854
+ "columnType": "UUID"
5855
+ },
5366
5856
  {
5367
5857
  "name": "itemId",
5368
5858
  "type": "text",
@@ -5389,6 +5879,13 @@
5389
5879
  "required": true,
5390
5880
  "related": "Learner",
5391
5881
  "columnType": "UUID"
5882
+ },
5883
+ {
5884
+ "name": "familyIntakeId",
5885
+ "type": "foreignKey",
5886
+ "required": false,
5887
+ "related": "FamilyIntake",
5888
+ "columnType": "UUID"
5392
5889
  }
5393
5890
  ],
5394
5891
  "methods": [
@@ -5404,6 +5901,9 @@
5404
5901
  {
5405
5902
  "name": "save",
5406
5903
  "async": true,
5904
+ "params": [
5905
+ "options?: SmrtSaveOptions"
5906
+ ],
5407
5907
  "returns": "Promise<this>"
5408
5908
  }
5409
5909
  ],
@@ -5556,6 +6056,9 @@
5556
6056
  {
5557
6057
  "name": "save",
5558
6058
  "async": true,
6059
+ "params": [
6060
+ "options?: SmrtSaveOptions"
6061
+ ],
5559
6062
  "returns": "Promise<this>"
5560
6063
  }
5561
6064
  ],
@@ -5695,6 +6198,9 @@
5695
6198
  {
5696
6199
  "name": "save",
5697
6200
  "async": true,
6201
+ "params": [
6202
+ "options?: SmrtSaveOptions"
6203
+ ],
5698
6204
  "returns": "Promise<this>"
5699
6205
  }
5700
6206
  ],
@@ -5828,6 +6334,9 @@
5828
6334
  {
5829
6335
  "name": "save",
5830
6336
  "async": true,
6337
+ "params": [
6338
+ "options?: SmrtSaveOptions"
6339
+ ],
5831
6340
  "returns": "Promise<this>"
5832
6341
  }
5833
6342
  ],
@@ -5885,14 +6394,14 @@
5885
6394
  "surfaces": [],
5886
6395
  "prompts": [],
5887
6396
  "relationshipsV2": {
5888
- "foreignKeyFields": 70,
5889
- "crossPackageRefFields": 6,
6397
+ "foreignKeyFields": 73,
6398
+ "crossPackageRefFields": 8,
5890
6399
  "junctionCollections": 2,
5891
6400
  "hierarchicalObjects": 0,
5892
6401
  "polymorphicAssociations": 0,
5893
- "uuidColumns": 298
6402
+ "uuidColumns": 320
5894
6403
  },
5895
- "agentDoc": "# smrt-education\n\nCatalog objects are optional-tenant scoped and have no generated REST, CLI, MCP,\nor AI surface. Applications use `CatalogService`, supplying their actor-bound\nauthorization decision and the trusted `TenantCollection.withTenantCatalogReadScope`\nadapter from smrt-users. Catalog authorization receives the exact shared collection\nexecutor; live session/permission checks must use that executor. That read scope may widen only an allowlisted catalog\ncollection's `list` to self, ancestors, and globals; it never authorizes a get,\nwrite, raw query, sibling, or descendant read.\n\n`personal-use-copy` courses and all `answer-key` lesson assets are private\nfamily material. Do not publish them, promote them, or expose them through a\nlearner-facing result. `LessonAsset` is the sole owner join for lesson files;\ndo not add asset-id fields to lesson subclasses.\n\nLearner objects require exact tenant ownership and close generated surfaces.\n`LearnerService` owns actor/resource authorization and transactional planning and\nstart-progress; see [learner contract](agents/learner-service.md). Guardian\nrelationships require a host decision about their type and effective terms.\nNever expose direct collection writes as learner handlers, reset progress on a\nretry, or treat an unscored nullable decimal as zero.\n\nSubmission capture, guardian grading and private PDF packet splitting use\n`SubmissionService`; see [submission contract](agents/submission-service.md).\nKeep asset metadata on the same transaction and compensate only newly planned\nfiles after rollback; never expose source URIs or accept learner grade patches.\n\nValidation: `pnpm --filter @happyvertical/smrt-education test`,\n`test:postgres`, `typecheck`, and `build`.\n\nPhysical workbook capture, immutable assessment/feedback history and descriptive\nevidence use [WorkbookService](agents/workbook-service.md). Keep provisional\nsharing separate from guardian Grade authority. Photo-first receipt/context\ncapture uses [WorkbookPhotoService](agents/photo-intake.md); covers/references\nnever create learning evidence, and blank exercises need explicit work intent.\n\nSource import: [host boundary and transaction contract](agents/source-import.md).\n`SourceImportService` requires host opt-in, matching active actor/tenant and\nexplicit licensing authorization; never add a system/global write bypass.\n",
6404
+ "agentDoc": "# smrt-education\n\nCatalog objects are optional-tenant scoped and have no generated REST, CLI, MCP,\nor AI surface. Applications use `CatalogService`, supplying their actor-bound\nauthorization decision and the trusted `TenantCollection.withTenantCatalogReadScope`\nadapter from smrt-users. Catalog authorization receives the exact shared collection\nexecutor; live session/permission checks must use that executor. That read scope may widen only an allowlisted catalog\ncollection's `list` to self, ancestors, and globals; it never authorizes a get,\nwrite, raw query, sibling, or descendant read.\n\n`personal-use-copy` courses and all `answer-key` lesson assets are private\nfamily material. Do not publish them, promote them, or expose them through a\nlearner-facing result. `LessonAsset` is the sole owner join for lesson files;\ndo not add asset-id fields to lesson subclasses.\n\nLearner objects require exact tenant ownership and close generated surfaces.\n`LearnerService` owns actor/resource authorization and transactional planning and\nstart-progress; see [learner contract](agents/learner-service.md). Guardian\nrelationships require a host decision about their type and effective terms.\nNever expose direct collection writes as learner handlers, reset progress on a\nretry, or treat an unscored nullable decimal as zero.\n\nSubmission capture, guardian grading and private PDF packet splitting use\n`SubmissionService`; see [submission contract](agents/submission-service.md).\nKeep asset metadata on the same transaction and compensate only newly planned\nfiles after rollback; never expose source URIs or accept learner grade patches.\n\nValidation: `pnpm --filter @happyvertical/smrt-education test`,\n`test:postgres`, `typecheck`, and `build`.\n\nPhysical workbook capture, immutable assessment/feedback history and descriptive\nevidence use [WorkbookService](agents/workbook-service.md). Keep provisional\nsharing separate from guardian Grade authority. Photo-first receipt/context\ncapture uses [WorkbookPhotoService](agents/photo-intake.md); covers/references\nnever create learning evidence, and blank exercises need explicit work intent.\n\nSource import: [host boundary and transaction contract](agents/source-import.md).\n`SourceImportService` requires host opt-in, matching active actor/tenant and\nexplicit licensing authorization; never add a system/global write bypass.\n\nFamily-owned unassigned originals and audited learner adoption use\n[FamilyIntakeService](agents/family-intake.md). Keep family source scope immutable;\nassignment alone never creates learning history or grants learner inbox access.\n",
5896
6405
  "moduleDocs": [
5897
6406
  {
5898
6407
  "path": "agents/learner-service.md",
@@ -5918,6 +6427,11 @@
5918
6427
  "path": "agents/source-import.md",
5919
6428
  "module": "source-import",
5920
6429
  "content": "# Source import integration\n\n`SourceImportService` is a server-side host boundary, with no generated REST,\nCLI, MCP or AI operation. Recipes remain metadata only. Provision a closed\n`CourseSource` in the owning tenant, then construct the service with the root\nSQL database and an actor-bound `SourceImportAuthorizer`. Enable tenancy and\ncall within `withTenant({ tenantId, userId })`; the request must match both.\nMissing context, a different actor/tenant and super-admin bypass fail closed.\n\nRegister Easy Peasy only after the host operator accepts its terms, using\n`registerEasyPeasy({ termsAccepted: true, fetchPage })`. Do not derive that\nboolean from an HTTP request. `fetchPage(url, { redirect: 'error' })` must reject\nredirects, bound time/size and return `{ html, url }`. It fetches the page only,\nnever a PDF. The service checks the approved HTTPS URL before fetching, checks\nthe response URL, limits HTML to 2 million characters, then parses the complete\npage before any write. There is no automatic registration or network access. Structural h1–h6 headings delimit day content, including trailing Resources\nsections; ordinary non-lesson bold instructions do not. Supported\nheading blocks are h1–h6 or a lesson marker as the first bold run in a\nparagraph/list item.\nRecognizable markers outside that layout, including multiple markers in one\nparagraph, fail closed rather than silently assigning a PDF to the wrong day.\n\nThe authorizer must verify the authenticated actor's management grant and the\nprovisioned tenant's family/group classification. Tenant has no built-in kind;\nneither hierarchy position nor client input establishes a family. Authorization\nis required before fetch and again inside the transaction; callbacks must be\nread-only decisions, since a rolled-back contention retry can call them again.\n\n`sharing` is a ceiling: private permits private-family import only; group and\nglobal permit private-family or group import. Group imports additionally require\nnonblank host-recorded `config.licenseEvidence` and an explicit host grant that\nvalidates that permission. Global/null destinations are unsupported and rejected;\nthere is no global/system bypass. Widening a source never promotes existing\nimports. Private imports are draft `personal-use-copy` courses and retain the\ncatalog's immutable owner/license and no-publication protection. A host may\ncreate a new licensed group source and import there after receiving permission.\n\nUse a stable `courseRef` independent of source URLs. Identities derive from the\nowning tenant, source row ID, course reference and lesson day; retain the source\nrow when updating policy. Changes to titles/page/PDF URLs update in place.\nMissing days are retained, not deleted, so enrollment, progress, submission and\nasset foreign keys remain valid. A changed lesson kind fails the whole import\nrather than replacing a row. Only title and pointer fields are refreshed; body,\nanswer keys, learner state and manually authored settings are never replaced.\nThe packet URL is returned as a source link and is not downloaded or mirrored.\n\nAll source policy rechecks and catalog mutations use collections bound to the\nsame SQL transaction. Embedded writes use the public write queue; PostgreSQL\nserializes an import identity with a transaction-scoped advisory lock. Only\nrolled-back busy/serialization/deadlock errors retry (at most three retries),\nwithout repeating fetch. Connection-invalidated and other failures propagate.\nDo not wrap the service in a caller transaction if the caller expects a durable\ncommit before returning; any outer transaction remains the caller's boundary.\n\nSQLite and PostgreSQL integration tests exercise real transactions and rollback.\nFull catalog children remain unavailable on DuckDB due to core's existing\nON UPDATE CASCADE/self-referential schema limitations documented in\n[catalog-service.md](catalog-service.md); no alternate schema is substituted.\nTests use synthetic local HTML and an injected fetch callback, never the network.\n\nGoogle Drive discovery defaults every record to `teacher`. A trusted host may\nmake only an exact reviewed file ID visible by passing `studentSafeFileIds`;\nfolder IDs and descendant membership never grant visibility. A teacher-marked\nfolder or name still wins over that allowlist. File shortcuts are excluded: a\nshortcut does not prove the target remains under a reviewed root or retains the\ntarget's teacher-path classification. Resync after changing the allowlist: the\ndurable sync upsert rewrites existing visibility rather than retaining a\nprevious learner classification.\n\nGeneric “Printable” and “Printables” labels identify lesson PDFs; course packets\nrequire explicit packet/whole-course/complete-course wording. Only actual href\nattributes supply pointers; data-href metadata does not.\n"
6430
+ },
6431
+ {
6432
+ "path": "agents/family-intake.md",
6433
+ "module": "family-intake",
6434
+ "content": "# Family intake\n\n`FamilyIntakeService` retains guardian-only originals before a learner is known.\nThe host supplies a trusted actor/tenant and a current family authorizer; each\nread, original download, assignment and adoption revalidates this authority on\nthe service's exact executor. Learners cannot browse the family inbox. Generated\nCRUD, CLI, MCP and AI surfaces remain closed.\n\nRetain the whole document with its source identity, delivery key, immutable hash\nand original private assets. Source delivery retries must preserve identical\ncontent and provenance. Email and scanner adapters are separate host configuration;\nthis service does not configure or select them. Trusted candidate DTOs and their\nquoted evidence are advisory. A guardian's active learner preference, visible\nmarks, uncertain names or a first-page guess never establish ownership. Mixed\nlearner PDFs stay unresolved until an explicit whole-document assignment is safe.\n\nAssignment records an immutable guardian decision with a revision and request\nkey. It does not create learner work. Adoption freezes that assignment and borrows\nthe exact original assets through learner photo ownership joins; it never rewrites\nsource confidentiality or creates grades. The existing photo resolution and\ncompleted-work capture preconditions still apply. Existing derived capture copies\nare permitted. Once adopted, a receipt cannot silently change learners; recovery\nrequires a separate explicit policy. An unadopted attribution can be corrected by\nanother audited decision with the current revision.\n\nFamily ownership retains originals beyond generic receipt expiry. Adoption does\nnot transfer or delete that ownership. Cleanup and rollback must preserve shared\nretained bytes and compensate only newly created files. Every access checks the\noriginal hash before adoption or download.\n\nValidation uses shared family workflows on real SQLite and isolated PostgreSQL;\nno AI providers, scanner/email services or containers are required.\n\nImport `FamilyIntakeService`, `receiveFamilyIntake` and\n`retainFamilyIntakeReceipt` from `@happyvertical/smrt-education/ingestion`.\nThe bridge uses the fixed `familyIntakeScopeId(tenantId)` namespace and public\n`getReceiptSource` to retain authoritative delivery identity. This namespace is\nnever an authorization grant. The host's `IngestionService.authorize` callback\nmust call the same current family authorizer on every operation, including direct\n`getEvidence`, `readEvidence` and `getReceiptSource` calls. For example, await\n`family.authorizeFamilyIntake({ tenantId: scope.tenantId, actorUserId: scope.actorId })`\nthen return true; propagate denial. Actor equality or tenant membership alone is\ninsufficient. This protects raw envelopes and rejected/unretained originals as\nwell as adopted receipts. Adoption permits only normal authorized learner work\nreads; it never grants the learner generic family ingestion access. A receive that\nsucceeds before education retention fails is repaired by retrying the same\nreceipt, never by inventing another delivery identity.\n\nDeploy manifest migrations for all three FamilyIntake models and the nullable\n`WorkbookPhotoIntake.familyIntakeId` FK before use. There is no runtime DDL.\nAdoption commits its immutable audit and exact photo/original joins atomically;\nthe family asset remains the sole original owner. Existing derived submission\ncopies use normal capture compensation. The exact adoption audit is required\nwhen validating borrowing joins, reads and immutable family-scope analysis.\n`countFamilyIntakes` counts unadopted receipts across the full inbox, while\n`listFamilyIntakes` pages the complete receipt history.\n\nAfter adoption, use the returned `photoIntakeId` with ordinary photo\nresolution/capture methods. Family-scope photo analysis checks the exact adopted\nitem/learner binding; learner-scoped uploads retain their existing strict scope.\nThe existing submission/assessment ingestion handlers still revalidate the\ncaptured learner/attempt. Temporary ingestion expiry does not prevent manual\nresolution/capture from retained education originals; re-analysis of an expired\nreceipt needs a separately authorized retained-input orchestration.\n\nThis initial contract assigns a whole receipt/document. It does not split a\nmixed-child PDF, automatically infer a child or configure a source adapter.\nFuture range adoption must preserve original hashes and page provenance; the\nretained immutable originals remain available for such an explicit workflow.\n\nSource-tree retention includes image/PDF attachments beneath metadata envelopes.\nA supported-media descendant of another supported original (for example a PDF's\npage thumbnail) stays in the evidence graph but is not duplicated as learner\nwork. Photo identification and captured-work analysis preservation use this same\noriginal-selection convention, so retained attachment hashes remain authoritative\nafter adoption and retries. The immutable graph retains only IDs, parent IDs, media types and hashes;\nit does not copy email bodies, arbitrary headers or credentials into public\nsource metadata. A source image such as an email logo is not automatically\nclassified as completed work. Whole-document attribution/classification remains\nan explicit guardian decision; ambiguous mixed contents need resolution.\n\nCustom source adapters must follow this supported convention: metadata parents\ncontain independent original attachments; descendants of supported media are\nrenditions of that media. Extraction outputs already live separately from source\nevidence. An adapter that uses media-child relationships for independently\nauthored attachments is unsupported by this bridge until its role is explicitly\nestablished; do not claim complete attachment fidelity for that shape or infer\nroles from first-page content. Full immutable evidence lineage is retained even\nwhen a rendition is excluded from capture pages.\n\nThe bridge rejects an entire receipt containing an unsupported independent\noriginal, including a mixed PDF/TIFF bundle, before family retention. Generic\nsource originals remain available for recovery; no partial family receipt or\nadoption is created. Hosts must acknowledge successful family import only after\nfamily retention succeeds and surface failed source imports. Known JSON\nmetadata wrappers and media descendants under the supported rendition convention\nare not independent originals.\n"
5921
6435
  }
5922
6436
  ],
5923
6437
  "recipes": [