enigma-memory 0.1.16 → 0.1.17

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.
@@ -774,3 +774,733 @@ export function verifyContextPack(args = {}) {
774
774
  canonical: canonical(publicPack),
775
775
  };
776
776
  }
777
+
778
+
779
+ const MEMORY_DRIVE_HEALTH_SCHEMA = 'enigma.memory_drive_health_report.v1';
780
+ const DEFAULT_HEALTH_NOW = '2026-06-25T00:00:00.000Z';
781
+ const DEFAULT_TOKENS_PER_MEMORY = 64;
782
+ const HEALTH_METRIC_NAMES = Object.freeze([
783
+ 'freshness',
784
+ 'duplicate_rate',
785
+ 'tombstone_risk',
786
+ 'stale_derived_artifacts',
787
+ 'retrieval_hit_rate',
788
+ 'token_reduction',
789
+ 'leakage_scan',
790
+ 'receipt_coverage',
791
+ 'connector_health',
792
+ 'sync_fork_risk',
793
+ ]);
794
+ const HEALTH_METRIC_WEIGHTS = Object.freeze({
795
+ freshness: 10,
796
+ duplicate_rate: 8,
797
+ tombstone_risk: 12,
798
+ stale_derived_artifacts: 10,
799
+ retrieval_hit_rate: 14,
800
+ token_reduction: 8,
801
+ leakage_scan: 14,
802
+ receipt_coverage: 10,
803
+ connector_health: 8,
804
+ sync_fork_risk: 6,
805
+ });
806
+ const HEALTH_EVIDENCE_PREFIX = Object.freeze({
807
+ freshness: 'freshness_scan',
808
+ duplicate_rate: 'dedupe_scan',
809
+ tombstone_risk: 'tombstone_scan',
810
+ stale_derived_artifacts: 'artifact_inventory',
811
+ retrieval_hit_rate: 'benchmark_report',
812
+ token_reduction: 'optimizer_report',
813
+ leakage_scan: 'leakage_scan',
814
+ receipt_coverage: 'receipt_inventory',
815
+ connector_health: 'connector_inventory',
816
+ sync_fork_risk: 'replica_roots',
817
+ });
818
+ const DEFAULT_HEALTH_POLICY = Object.freeze({
819
+ freshness_window_hours: 48,
820
+ freshness_healthy_ratio: 0.95,
821
+ freshness_watch_ratio: 0.85,
822
+ freshness_degraded_ratio: 0.7,
823
+ duplicate_rate_watch_floor: 0.02,
824
+ duplicate_rate_degraded_floor: 0.05,
825
+ duplicate_rate_critical_floor: 0.12,
826
+ tombstone_ack_window_hours: 24,
827
+ retrieval_top_k: 5,
828
+ hit_at_k_floor: 0.9,
829
+ exact_coverage_floor: 0.85,
830
+ abstention_correctness_floor: 0.95,
831
+ token_reduction_floor: 0.5,
832
+ receipt_coverage_healthy_floor: 0.99,
833
+ receipt_coverage_watch_floor: 0.95,
834
+ receipt_coverage_degraded_floor: 0.85,
835
+ connector_max_error_rate_24h: 0.01,
836
+ sync_max_read_only_lag_versions: 1,
837
+ });
838
+ const HEALTH_FORBIDDEN_KEY_RE = /(?:^|_)(?:raw|plaintext|plain_text|prompt|prompts|message|messages|text|content|document|documents|transcript|transcripts|completion|completions|embedding|embeddings|provider_response|provider_responses|response_body|credential|credentials|api_key|secret|password|private_key|seed|seed_phrase|mnemonic|tenant_name|customer_name|organization_name|org_name)(?:$|_)/iu;
839
+ const HEALTH_SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16}|(?:seed phrase|mnemonic phrase|raw memory|private prompt|full transcript|provider response|embedding vector))/iu;
840
+ const HEALTH_SAFE_KEYS = new Set([
841
+ 'transaction_submitted',
842
+ 'raw_memory_on_chain',
843
+ 'provider_deletion_claim',
844
+ 'model_forgetting_claim',
845
+ 'hosted_saas_claim',
846
+ 'report_ref',
847
+ 'drive_ref',
848
+ 'namespace_ref',
849
+ 'source_root',
850
+ 'policy_ref',
851
+ 'artifact_root',
852
+ 'instruction_ref',
853
+ 'latest_anchor_batch_ref',
854
+ 'private_payloads_included',
855
+ 'connector_bodies_included',
856
+ 'identity_labels_included',
857
+ 'secret_material_included',
858
+ 'provider_bodies_included',
859
+ 'secret_value_hits',
860
+ 'forbidden_payload_key_hits',
861
+ 'secret_value_hits_allowed',
862
+ 'forbidden_payload_key_hits_allowed',
863
+ ]);
864
+
865
+ function clamp01(value) {
866
+ if (!Number.isFinite(value)) return 0;
867
+ if (value < 0) return 0;
868
+ if (value > 1) return 1;
869
+ return value;
870
+ }
871
+
872
+ function bandScore(status, goodness) {
873
+ const r = clamp01(goodness);
874
+ switch (status) {
875
+ case 'healthy':
876
+ return 90 + Math.round(10 * r);
877
+ case 'watch':
878
+ return 75 + Math.round(14 * r);
879
+ case 'degraded':
880
+ return 50 + Math.round(24 * r);
881
+ case 'critical':
882
+ return Math.round(49 * r);
883
+ default:
884
+ return 0;
885
+ }
886
+ }
887
+
888
+ function statusFromScore(score) {
889
+ if (score >= 90) return 'healthy';
890
+ if (score >= 75) return 'watch';
891
+ if (score >= 50) return 'degraded';
892
+ return 'critical';
893
+ }
894
+
895
+ function ageHours(iso, nowMs) {
896
+ const t = Date.parse(iso);
897
+ if (!Number.isFinite(t)) return Number.POSITIVE_INFINITY;
898
+ return Math.max(0, (nowMs - t) / 3600000);
899
+ }
900
+
901
+ function healthScan(value, path, hits) {
902
+ if (typeof value === 'string') {
903
+ if (HEALTH_SECRET_VALUE_RE.test(value)) hits.secret.push(path || '<root>');
904
+ return;
905
+ }
906
+ if (Array.isArray(value)) {
907
+ value.forEach((item, index) => healthScan(item, `${path}[${index}]`, hits));
908
+ return;
909
+ }
910
+ if (value !== null && typeof value === 'object') {
911
+ for (const [key, child] of Object.entries(value)) {
912
+ const childPath = path ? `${path}.${key}` : key;
913
+ if (HEALTH_FORBIDDEN_KEY_RE.test(key) && !HEALTH_SAFE_KEYS.has(key)) hits.keys.push(childPath);
914
+ healthScan(child, childPath, hits);
915
+ }
916
+ }
917
+ }
918
+
919
+ function healthDigest(value) {
920
+ return `sha256:${sha256Hex(canonical(value))}`;
921
+ }
922
+
923
+ function healthEvidenceRef(metricName, observed) {
924
+ return `${HEALTH_EVIDENCE_PREFIX[metricName]}_${healthDigest(observed)}`;
925
+ }
926
+
927
+ function healthMetric(metricName, { status, score, observed, thresholds, evidenceRef, recommendedActions }) {
928
+ const actions = Array.isArray(recommendedActions) ? recommendedActions.filter(Boolean) : [];
929
+ return {
930
+ status,
931
+ score,
932
+ observed,
933
+ thresholds,
934
+ evidence_refs: evidenceRef ? [evidenceRef] : [],
935
+ recommended_actions: actions,
936
+ };
937
+ }
938
+
939
+ function vaultRecord(vault, addr) {
940
+ if (vault?.__getRecord) {
941
+ try {
942
+ return vault.__getRecord(addr) ?? null;
943
+ } catch {
944
+ return null;
945
+ }
946
+ }
947
+ if (vault?.memories instanceof Map) return vault.memories.get(addr) ?? null;
948
+ if (Array.isArray(vault?.memory_objects)) return vault.memory_objects.find((record) => record?.memory_addr === addr) ?? null;
949
+ return null;
950
+ }
951
+
952
+ function driveIdentity(vault, passport) {
953
+ const bundleVault = vault?.schema === 'enigma.vault_bundle.v1' ? vault.vault : vault;
954
+ return {
955
+ vault_id: bundleVault?.vault_id ?? vault?.vault_id ?? passport?.vault?.vault_id ?? 'local-vault',
956
+ tenant_id: bundleVault?.tenant_id ?? vault?.tenant_id ?? passport?.owner?.subject_id ?? 'local',
957
+ subject_id: bundleVault?.subject_id ?? vault?.subject_id ?? passport?.owner?.subject_id ?? 'local-subject',
958
+ policy_id: bundleVault?.policy_id ?? vault?.policy_id ?? 'local-default',
959
+ };
960
+ }
961
+
962
+ function normalizeContextPacks(args) {
963
+ const packs = [];
964
+ const fromArgs = args.contextPacks ?? args.context_packs ?? [];
965
+ const single = args.contextPack ?? args.context_pack ?? args.pack;
966
+ const list = single ? [single] : fromArgs;
967
+ for (const pack of Array.isArray(list) ? list : []) {
968
+ if (!pack) continue;
969
+ packs.push({
970
+ artifact_type: pack.artifact_type ?? 'context_pack',
971
+ source_root: pack.active_set_root ?? pack.activeSetRoot ?? pack.source_root ?? pack.sourceRoot,
972
+ generated_at: pack.generated_at ?? pack.generatedAt,
973
+ memory_addresses: pack.memory_addresses ?? [],
974
+ serving: pack.serving !== false,
975
+ });
976
+ }
977
+ const extras = args.derivedArtifacts ?? args.derived_artifacts ?? [];
978
+ for (const artifact of Array.isArray(extras) ? extras : []) {
979
+ if (!artifact) continue;
980
+ packs.push({
981
+ artifact_type: artifact.artifact_type ?? artifact.artifactType ?? 'derived_artifact',
982
+ source_root: artifact.source_root ?? artifact.sourceRoot,
983
+ generated_at: artifact.generated_at ?? artifact.generatedAt,
984
+ memory_addresses: artifact.memory_addresses ?? [],
985
+ serving: artifact.serving !== false,
986
+ });
987
+ }
988
+ return packs;
989
+ }
990
+
991
+ function computeFreshness(records, policy, nowMs) {
992
+ const activeRefCount = records.length;
993
+ const thresholds = {
994
+ fresh_records_ratio_watch_floor: policy.freshness_watch_ratio,
995
+ fresh_records_ratio_degraded_floor: policy.freshness_degraded_ratio,
996
+ policy_window_hours: policy.freshness_window_hours,
997
+ };
998
+ if (activeRefCount === 0) {
999
+ const observed = { active_ref_count: 0, fresh_records_ratio: 1, p95_active_age_hours: 0, oldest_unrefreshed_age_hours: 0 };
1000
+ return healthMetric('freshness', { status: 'healthy', score: 100, observed, thresholds, evidenceRef: healthEvidenceRef('freshness', observed), recommendedActions: [] });
1001
+ }
1002
+ const finiteAges = [];
1003
+ let missingTimestamps = 0;
1004
+ for (const record of records) {
1005
+ const age = ageHours(record?.updated_at, nowMs);
1006
+ if (Number.isFinite(age)) finiteAges.push(age);
1007
+ else missingTimestamps += 1;
1008
+ }
1009
+ finiteAges.sort((a, b) => a - b);
1010
+ const freshCount = finiteAges.filter((age) => age <= policy.freshness_window_hours).length;
1011
+ const ratio = activeRefCount > 0 ? freshCount / activeRefCount : 1;
1012
+ const p95Index = finiteAges.length === 0 ? 0 : Math.min(finiteAges.length - 1, Math.floor(finiteAges.length * 0.95));
1013
+ const p95Age = finiteAges.length === 0 ? Number.POSITIVE_INFINITY : finiteAges[p95Index];
1014
+ const oldestAge = finiteAges.length === 0 ? Number.POSITIVE_INFINITY : finiteAges[finiteAges.length - 1];
1015
+ const observed = {
1016
+ active_ref_count: activeRefCount,
1017
+ fresh_records_ratio: roundRatio(ratio),
1018
+ p95_active_age_hours: Number.isFinite(p95Age) ? Math.round(p95Age) : null,
1019
+ oldest_unrefreshed_age_hours: Number.isFinite(oldestAge) ? Math.round(oldestAge) : null,
1020
+ };
1021
+ let status;
1022
+ if (missingTimestamps > 0 || ratio < policy.freshness_degraded_ratio) status = 'critical';
1023
+ else if (ratio < policy.freshness_watch_ratio || oldestAge > 2 * policy.freshness_window_hours) status = 'degraded';
1024
+ else if (ratio < policy.freshness_healthy_ratio || p95Age > policy.freshness_window_hours) status = 'watch';
1025
+ else status = 'healthy';
1026
+ const recommendedActions = [];
1027
+ if (status !== 'healthy') {
1028
+ recommendedActions.push('Run local revalidation for stale namespaces.');
1029
+ if (oldestAge > policy.freshness_window_hours) recommendedActions.push('Rebuild the retrieval index for stale partitions.');
1030
+ if (status === 'critical') recommendedActions.push('Restore freshness metadata for active records before anchoring.');
1031
+ }
1032
+ return healthMetric('freshness', { status, score: bandScore(status, ratio), observed, thresholds, evidenceRef: healthEvidenceRef('freshness', observed), recommendedActions });
1033
+ }
1034
+
1035
+ function computeDuplicateRate(records, policy) {
1036
+ const activeRefCount = records.length;
1037
+ const thresholds = {
1038
+ watch_floor: policy.duplicate_rate_watch_floor,
1039
+ degraded_floor: policy.duplicate_rate_degraded_floor,
1040
+ critical_floor: policy.duplicate_rate_critical_floor,
1041
+ };
1042
+ const hashCounts = new Map();
1043
+ for (const record of records) {
1044
+ const hash = record?.content_hash ?? record?.content_commitment ?? record?.memory_addr;
1045
+ hashCounts.set(hash, (hashCounts.get(hash) ?? 0) + 1);
1046
+ }
1047
+ let duplicateCandidateCount = 0;
1048
+ for (const count of hashCounts.values()) {
1049
+ if (count > 1) duplicateCandidateCount += count - 1;
1050
+ }
1051
+ const duplicateRate = activeRefCount > 0 ? duplicateCandidateCount / activeRefCount : 0;
1052
+ const observed = {
1053
+ active_ref_count: activeRefCount,
1054
+ duplicate_candidate_count: duplicateCandidateCount,
1055
+ duplicate_rate: roundRatio(duplicateRate),
1056
+ dedupe_savings_estimated_tokens: duplicateCandidateCount * DEFAULT_TOKENS_PER_MEMORY,
1057
+ };
1058
+ let status;
1059
+ if (duplicateRate > policy.duplicate_rate_critical_floor) status = 'critical';
1060
+ else if (duplicateRate >= policy.duplicate_rate_degraded_floor) status = 'degraded';
1061
+ else if (duplicateRate >= policy.duplicate_rate_watch_floor) status = 'watch';
1062
+ else status = 'healthy';
1063
+ const recommendedActions = [];
1064
+ if (status !== 'healthy') {
1065
+ recommendedActions.push('Merge duplicate candidates using local canonical refs.');
1066
+ recommendedActions.push('Preserve receipt lineage for merged records.');
1067
+ }
1068
+ return healthMetric('duplicate_rate', { status, score: bandScore(status, 1 - duplicateRate), observed, thresholds, evidenceRef: healthEvidenceRef('duplicate_rate', observed), recommendedActions });
1069
+ }
1070
+
1071
+ function computeTombstoneRisk({ vault, tombstoneSet, deleteReceiptAddrs, artifacts, connectorReplayWindowHours, policy }) {
1072
+ const tombstoneCount = tombstoneSet.size;
1073
+ const thresholds = { max_ack_lag_hours: policy.tombstone_ack_window_hours };
1074
+ let unsettled = 0;
1075
+ for (const addr of tombstoneSet) {
1076
+ if (!deleteReceiptAddrs.has(addr)) unsettled += 1;
1077
+ }
1078
+ const artifactsReferencingTombstones = artifacts.filter((artifact) => artifact.memory_addresses.some((addr) => tombstoneSet.has(addr)));
1079
+ const derivedReferencingTombstones = artifactsReferencingTombstones.length;
1080
+ const servingReferencingTombstones = artifactsReferencingTombstones.filter((artifact) => artifact.serving).length;
1081
+ const replayWindow = Math.max(0, connectorReplayWindowHours ?? 0);
1082
+ const observed = {
1083
+ tombstone_count: tombstoneCount,
1084
+ unsettled_tombstone_count: unsettled,
1085
+ derived_artifacts_referencing_tombstones: derivedReferencingTombstones,
1086
+ tombstone_replay_window_hours: Math.round(replayWindow),
1087
+ };
1088
+ let status;
1089
+ if (servingReferencingTombstones > 0) status = 'critical';
1090
+ else if (derivedReferencingTombstones > 0 || replayWindow > policy.tombstone_ack_window_hours) status = 'degraded';
1091
+ else if (tombstoneCount > 0 && (unsettled > 0 || replayWindow > 0)) status = 'watch';
1092
+ else status = 'healthy';
1093
+ const recommendedActions = [];
1094
+ if (status !== 'healthy') {
1095
+ if (derivedReferencingTombstones > 0) recommendedActions.push('Invalidate derived artifacts that depend on tombstoned refs.');
1096
+ if (servingReferencingTombstones > 0) recommendedActions.push('Quarantine serving artifacts that can replay tombstoned content.');
1097
+ recommendedActions.push('Rebuild context packs and exports from active refs only.');
1098
+ }
1099
+ const goodness = tombstoneCount === 0 ? 1 : 1 - clamp01((unsettled + derivedReferencingTombstones) / Math.max(1, tombstoneCount));
1100
+ return healthMetric('tombstone_risk', { status, score: bandScore(status, goodness), observed, thresholds, evidenceRef: healthEvidenceRef('tombstone_risk', observed), recommendedActions });
1101
+ }
1102
+
1103
+ function computeStaleDerivedArtifacts({ artifacts, currentRoot, nowMs, policy }) {
1104
+ const thresholds = { serving_path_stale_artifacts_allowed: 0 };
1105
+ const evaluated = artifacts.map((artifact) => ({
1106
+ ...artifact,
1107
+ stale: Boolean(artifact.source_root) && artifact.source_root !== currentRoot,
1108
+ lag_hours: ageHours(artifact.generated_at, nowMs),
1109
+ }));
1110
+ const staleArtifacts = evaluated.filter((artifact) => artifact.stale);
1111
+ const staleServing = staleArtifacts.filter((artifact) => artifact.serving);
1112
+ const staleTypes = [...new Set(staleArtifacts.map((artifact) => artifact.artifact_type))].sort();
1113
+ const maxLagHours = staleArtifacts.reduce((max, artifact) => (Number.isFinite(artifact.lag_hours) ? Math.max(max, artifact.lag_hours) : max), 0);
1114
+ const observed = {
1115
+ stale_artifact_count: staleArtifacts.length,
1116
+ artifact_types_stale: staleTypes,
1117
+ max_artifact_lag_versions: staleArtifacts.length > 0 ? 1 : 0,
1118
+ max_artifact_lag_hours: Number.isFinite(maxLagHours) ? Math.round(maxLagHours) : 0,
1119
+ };
1120
+ let status;
1121
+ if (staleServing.length > 0) status = 'degraded';
1122
+ else if (staleArtifacts.length > 0) status = 'watch';
1123
+ else status = 'healthy';
1124
+ const recommendedActions = [];
1125
+ if (status !== 'healthy') {
1126
+ recommendedActions.push('Rebuild active derived artifacts from the current source root.');
1127
+ if (staleServing.length > 0) recommendedActions.push('Quarantine proof packets made from stale roots.');
1128
+ recommendedActions.push('Require artifact builders to declare source_root and artifact_root.');
1129
+ }
1130
+ const total = Math.max(1, evaluated.length);
1131
+ const goodness = 1 - clamp01(staleArtifacts.length / total);
1132
+ return healthMetric('stale_derived_artifacts', { status, score: bandScore(status, goodness), thresholds, observed, evidenceRef: healthEvidenceRef('stale_derived_artifacts', observed), recommendedActions });
1133
+ }
1134
+
1135
+ function computeRetrievalHitRate({ benchmarkSummary, policy }) {
1136
+ const thresholds = {
1137
+ hit_at_k_floor: policy.hit_at_k_floor,
1138
+ exact_coverage_floor: policy.exact_coverage_floor,
1139
+ abstention_correctness_floor: policy.abstention_correctness_floor,
1140
+ };
1141
+ if (!benchmarkSummary) {
1142
+ const observed = { probe_count: 0, top_k: policy.retrieval_top_k, hit_at_k: 0, exact_coverage: 0, abstention_correctness: 0, measured: false };
1143
+ return healthMetric('retrieval_hit_rate', { status: 'healthy', score: 90, observed, thresholds, evidenceRef: healthEvidenceRef('retrieval_hit_rate', observed), recommendedActions: ['Supply benchmark_summary to measure retrieval hit rate.'] });
1144
+ }
1145
+ const probeCount = nonNegativeInt(benchmarkSummary.probe_count ?? benchmarkSummary.probeCount);
1146
+ const topK = nonNegativeInt(benchmarkSummary.top_k ?? benchmarkSummary.topK ?? policy.retrieval_top_k);
1147
+ const hitAtK = clampRatio(benchmarkSummary.hit_at_k ?? benchmarkSummary.hitAtK);
1148
+ const exactCoverage = clampRatio(benchmarkSummary.exact_coverage ?? benchmarkSummary.exactCoverage);
1149
+ const abstention = clampRatio(benchmarkSummary.abstention_correctness ?? benchmarkSummary.abstentionCorrectness);
1150
+ const returnsTombstoned = Boolean(benchmarkSummary.returned_tombstoned_refs ?? benchmarkSummary.returnedTombstonedRefs);
1151
+ const observed = { probe_count: probeCount, top_k: topK, hit_at_k: hitAtK, exact_coverage: exactCoverage, abstention_correctness: abstention, measured: true };
1152
+ let status;
1153
+ if (returnsTombstoned || probeCount === 0) status = 'critical';
1154
+ else if (hitAtK < policy.hit_at_k_floor || exactCoverage < policy.exact_coverage_floor || abstention < policy.abstention_correctness_floor) status = 'degraded';
1155
+ else if (hitAtK < policy.hit_at_k_floor + 0.05 || exactCoverage < policy.exact_coverage_floor + 0.05 || abstention < policy.abstention_correctness_floor + 0.05) status = 'watch';
1156
+ else status = 'healthy';
1157
+ const recommendedActions = [];
1158
+ if (status !== 'healthy') {
1159
+ recommendedActions.push('Rebuild retrieval indexes.');
1160
+ recommendedActions.push('Inspect namespace filters and capability scopes.');
1161
+ recommendedActions.push('Compare against the last healthy benchmark report hash.');
1162
+ }
1163
+ const goodness = (hitAtK + exactCoverage + abstention) / 3;
1164
+ return healthMetric('retrieval_hit_rate', { status, score: bandScore(status, goodness), observed, thresholds, evidenceRef: healthEvidenceRef('retrieval_hit_rate', observed), recommendedActions });
1165
+ }
1166
+
1167
+ function computeTokenReduction({ activeCount, contextPackProvided, selectedCount, retrievalGuardPassed, policy }) {
1168
+ const thresholds = { token_reduction_floor: policy.token_reduction_floor, quality_guard_required: true };
1169
+ if (!contextPackProvided) {
1170
+ const observed = { baseline_estimated_tokens: activeCount * DEFAULT_TOKENS_PER_MEMORY, selected_estimated_tokens: 0, token_reduction_ratio: 0, quality_guard_passed: retrievalGuardPassed, measured: false };
1171
+ return healthMetric('token_reduction', { status: 'healthy', score: 90, observed, thresholds, evidenceRef: healthEvidenceRef('token_reduction', observed), recommendedActions: ['Supply a context pack or benchmark summary to measure token reduction.'] });
1172
+ }
1173
+ const baseline = activeCount * DEFAULT_TOKENS_PER_MEMORY;
1174
+ const selected = Math.max(0, selectedCount) * DEFAULT_TOKENS_PER_MEMORY;
1175
+ const ratio = baseline > 0 ? clamp01(1 - selected / baseline) : 0;
1176
+ const observed = { baseline_estimated_tokens: baseline, selected_estimated_tokens: selected, token_reduction_ratio: roundRatio(ratio), quality_guard_passed: retrievalGuardPassed, measured: true };
1177
+ let status;
1178
+ if (!retrievalGuardPassed) status = ratio >= policy.token_reduction_floor ? 'degraded' : 'critical';
1179
+ else if (ratio >= policy.token_reduction_floor) status = 'healthy';
1180
+ else status = 'watch';
1181
+ const recommendedActions = [];
1182
+ if (status !== 'healthy') {
1183
+ recommendedActions.push('Tune ranking thresholds only if the retrieval guard remains satisfied.');
1184
+ recommendedActions.push('Dedupe before reducing top-k.');
1185
+ recommendedActions.push('Never optimize tokens by suppressing required evidence refs.');
1186
+ }
1187
+ return healthMetric('token_reduction', { status, score: bandScore(status, ratio), observed, thresholds, evidenceRef: healthEvidenceRef('token_reduction', observed), recommendedActions });
1188
+ }
1189
+
1190
+ function computeLeakageScan({ reportBody, scanInputs }) {
1191
+ const thresholds = { forbidden_payload_key_hits_allowed: 0, secret_value_hits_allowed: 0 };
1192
+ const hits = { keys: [], secret: [] };
1193
+ for (const input of scanInputs) healthScan(input, '', hits);
1194
+ healthScan(reportBody, '', hits);
1195
+ const forbiddenHits = hits.keys.length;
1196
+ const secretHits = hits.secret.length;
1197
+ const unsafeArtifactRefs = [];
1198
+ if (forbiddenHits > 0 || secretHits > 0) unsafeArtifactRefs.push(`leakage_scan_${healthDigest({ forbiddenHits, secretHits })}`);
1199
+ const observed = {
1200
+ scanned_artifact_count: scanInputs.length,
1201
+ forbidden_payload_key_hits: forbiddenHits,
1202
+ secret_value_hits: secretHits,
1203
+ unsafe_artifact_refs: unsafeArtifactRefs,
1204
+ };
1205
+ let status;
1206
+ if (forbiddenHits > 0 || secretHits > 0) status = 'critical';
1207
+ else status = 'healthy';
1208
+ const recommendedActions = [];
1209
+ if (status !== 'healthy') {
1210
+ recommendedActions.push('Quarantine unsafe artifacts.');
1211
+ recommendedActions.push('Regenerate reports from public-safe fields only.');
1212
+ recommendedActions.push('Block proof-network packet creation until the leakage scan is clean.');
1213
+ }
1214
+ return healthMetric('leakage_scan', { status, score: status === 'healthy' ? 100 : bandScore('critical', 0), thresholds, observed, evidenceRef: healthEvidenceRef('leakage_scan', observed), recommendedActions });
1215
+ }
1216
+
1217
+ function computeReceiptCoverage({ activeAddrs, receipts, latestAnchorBatchRef, currentRoots, policy }) {
1218
+ const thresholds = {
1219
+ healthy_floor: policy.receipt_coverage_healthy_floor,
1220
+ watch_floor: policy.receipt_coverage_watch_floor,
1221
+ degraded_floor: policy.receipt_coverage_degraded_floor,
1222
+ };
1223
+ const activeRefCount = activeAddrs.size;
1224
+ const coveredAddrs = new Set();
1225
+ let invalidReceiptCount = 0;
1226
+ let rootMismatch = false;
1227
+ for (const receipt of receipts) {
1228
+ if (!receipt || typeof receipt !== 'object') continue;
1229
+ const addr = receipt.memory_addr ?? receipt.memoryAddr;
1230
+ if (typeof addr === 'string') coveredAddrs.add(addr);
1231
+ if (receipt.active_set_root && receipt.active_set_root !== currentRoots.active_set_root) {
1232
+ // a stale receipt root is expected for historical events; only a missing root on the latest state is a mismatch
1233
+ }
1234
+ if (receipt.schema && receipt.schema !== 'enigma.receipt.v1') invalidReceiptCount += 1;
1235
+ }
1236
+ if (activeRefCount === 0) {
1237
+ const observed = { active_ref_count: 0, covered_ref_count: 0, receipt_coverage_ratio: 1, invalid_receipt_count: invalidReceiptCount, latest_anchor_batch_ref: latestAnchorBatchRef ?? null };
1238
+ return healthMetric('receipt_coverage', { status: 'healthy', score: 100, observed, thresholds, evidenceRef: healthEvidenceRef('receipt_coverage', observed), recommendedActions: [] });
1239
+ }
1240
+ let coveredCount = 0;
1241
+ for (const addr of activeAddrs) {
1242
+ if (coveredAddrs.has(addr)) coveredCount += 1;
1243
+ }
1244
+ const ratio = coveredCount / activeRefCount;
1245
+ const observed = {
1246
+ active_ref_count: activeRefCount,
1247
+ covered_ref_count: coveredCount,
1248
+ receipt_coverage_ratio: roundRatio(ratio),
1249
+ invalid_receipt_count: invalidReceiptCount,
1250
+ latest_anchor_batch_ref: latestAnchorBatchRef ?? null,
1251
+ };
1252
+ let status;
1253
+ if (rootMismatch || ratio < policy.receipt_coverage_degraded_floor) status = 'critical';
1254
+ else if (invalidReceiptCount > 0 || ratio < policy.receipt_coverage_watch_floor) status = 'degraded';
1255
+ else if (ratio < policy.receipt_coverage_healthy_floor) status = 'watch';
1256
+ else status = 'healthy';
1257
+ const recommendedActions = [];
1258
+ if (status !== 'healthy') {
1259
+ recommendedActions.push('Issue local receipts for uncovered active refs.');
1260
+ recommendedActions.push('Regenerate inclusion roots after compaction.');
1261
+ recommendedActions.push('Verify anchor batches before external publication.');
1262
+ }
1263
+ return healthMetric('receipt_coverage', { status, score: bandScore(status, ratio), observed, thresholds, evidenceRef: healthEvidenceRef('receipt_coverage', observed), recommendedActions });
1264
+ }
1265
+
1266
+ function computeConnectorHealth({ connectorSummary, policy }) {
1267
+ const thresholds = { cursor_gap_count_allowed: 0, max_error_rate_24h: policy.connector_max_error_rate_24h };
1268
+ if (!connectorSummary) {
1269
+ const observed = { connector_count: 0, healthy_connector_count: 0, lagging_connector_count: 0, error_rate_24h: 0, cursor_gap_count: 0, measured: false };
1270
+ return healthMetric('connector_health', { status: 'healthy', score: 100, observed, thresholds, evidenceRef: healthEvidenceRef('connector_health', observed), recommendedActions: ['Supply connector_summary to measure connector health.'] });
1271
+ }
1272
+ const connectorCount = nonNegativeInt(connectorSummary.connector_count ?? connectorSummary.connectorCount);
1273
+ const healthy = nonNegativeInt(connectorSummary.healthy_connector_count ?? connectorSummary.healthyConnectorCount);
1274
+ const lagging = nonNegativeInt(connectorSummary.lagging_connector_count ?? connectorSummary.laggingConnectorCount);
1275
+ const errorRate = clampRatio(connectorSummary.error_rate_24h ?? connectorSummary.errorRate24h);
1276
+ const cursorGaps = nonNegativeInt(connectorSummary.cursor_gap_count ?? connectorSummary.cursorGapCount);
1277
+ const observed = { connector_count: connectorCount, healthy_connector_count: healthy, lagging_connector_count: lagging, error_rate_24h: roundRatio(errorRate), cursor_gap_count: cursorGaps, measured: true };
1278
+ let status;
1279
+ if (cursorGaps > 0) status = 'critical';
1280
+ else if (errorRate > policy.connector_max_error_rate_24h || lagging > 0) status = 'degraded';
1281
+ else status = 'healthy';
1282
+ const recommendedActions = [];
1283
+ if (status !== 'healthy') {
1284
+ recommendedActions.push('Pause unhealthy connector scopes before replay.');
1285
+ recommendedActions.push('Repair cursor gaps from receipt refs, not raw provider payloads.');
1286
+ recommendedActions.push('Require connector imports to emit idempotency refs.');
1287
+ }
1288
+ const goodness = connectorCount === 0 ? 1 : healthy / connectorCount;
1289
+ return healthMetric('connector_health', { status, score: bandScore(status, goodness), observed, thresholds, evidenceRef: healthEvidenceRef('connector_health', observed), recommendedActions });
1290
+ }
1291
+
1292
+ function computeSyncForkRisk({ replicas, currentRoot, policy }) {
1293
+ const thresholds = { active_root_disagreement_allowed: 0, conflicting_capability_count_allowed: 0 };
1294
+ const replicaList = Array.isArray(replicas) ? replicas : [];
1295
+ const replicaCount = replicaList.length;
1296
+ if (replicaCount === 0) {
1297
+ const observed = { replica_count: 0, root_disagreement_count: 0, max_root_lag_versions: 0, unmerged_branch_count: 0, conflicting_capability_count: 0, measured: false };
1298
+ return healthMetric('sync_fork_risk', { status: 'healthy', score: 100, observed, thresholds, evidenceRef: healthEvidenceRef('sync_fork_risk', observed), recommendedActions: ['Supply replicas to measure sync fork risk.'] });
1299
+ }
1300
+ let disagreement = 0;
1301
+ let maxLag = 0;
1302
+ let unmerged = 0;
1303
+ let conflicting = 0;
1304
+ for (const replica of replicaList) {
1305
+ const reportedRoot = replica.reported_root ?? replica.reportedRoot;
1306
+ const lag = nonNegativeInt(replica.lag_versions ?? replica.lagVersions);
1307
+ const isActive = replica.active !== false;
1308
+ const conflicts = nonNegativeInt(replica.conflicting_capabilities ?? replica.conflictingCapabilities);
1309
+ if (reportedRoot && reportedRoot !== currentRoot && isActive) disagreement += 1;
1310
+ maxLag = Math.max(maxLag, lag);
1311
+ if (replica.unmerged_branch ?? replica.unmergedBranch) unmerged += 1;
1312
+ conflicting += conflicts;
1313
+ }
1314
+ const observed = { replica_count: replicaCount, root_disagreement_count: disagreement, max_root_lag_versions: maxLag, unmerged_branch_count: unmerged, conflicting_capability_count: conflicting, measured: true };
1315
+ let status;
1316
+ if (conflicting > 0) status = 'critical';
1317
+ else if (disagreement > 0) status = 'degraded';
1318
+ else if (maxLag > policy.sync_max_read_only_lag_versions || unmerged > 0) status = 'watch';
1319
+ else status = 'healthy';
1320
+ const recommendedActions = [];
1321
+ if (status !== 'healthy') {
1322
+ recommendedActions.push('Freeze write grants for forked namespaces.');
1323
+ recommendedActions.push('Merge by public-safe root/ref lineage and tombstone nullifiers.');
1324
+ recommendedActions.push('Publish only the post-merge root after validation.');
1325
+ }
1326
+ const goodness = 1 - clamp01((disagreement + conflicting) / Math.max(1, replicaCount));
1327
+ return healthMetric('sync_fork_risk', { status, score: bandScore(status, goodness), observed, thresholds, evidenceRef: healthEvidenceRef('sync_fork_risk', observed), recommendedActions });
1328
+ }
1329
+
1330
+ function nonNegativeInt(value) {
1331
+ const n = Number(value);
1332
+ if (!Number.isFinite(n) || n < 0) return 0;
1333
+ return Math.floor(n);
1334
+ }
1335
+
1336
+ function roundRatio(value) {
1337
+ if (!Number.isFinite(value)) return 0;
1338
+ return Math.round(value * 10000) / 10000;
1339
+ }
1340
+
1341
+ function clampRatio(value) {
1342
+ return clamp01(Number.isFinite(Number(value)) ? Number(value) : 0);
1343
+ }
1344
+
1345
+ export function createMemoryDriveHealthReport(args = {}) {
1346
+ const vault = args.vault;
1347
+ const passport = args.passport;
1348
+ const policy = { ...DEFAULT_HEALTH_POLICY, ...(args.policy ?? {}) };
1349
+ const createdAt = nowIso(args.now ?? DEFAULT_HEALTH_NOW);
1350
+ const nowMs = Date.parse(createdAt);
1351
+ const identity = driveIdentity(vault, passport);
1352
+ const currentRoots = rootsFromVault(vault);
1353
+ const activeAddrs = activeAddressesFrom(vault);
1354
+ const tombstoneSet = tombstoneAddressesFrom(vault);
1355
+ const records = [...activeAddrs].map((addr) => vaultRecord(vault, addr)).filter(Boolean);
1356
+ const receipts = Array.isArray(vault?.receipts) ? vault.receipts : [];
1357
+ const deleteReceiptAddrs = new Set(receipts.filter((receipt) => receipt?.operation === 'delete' && receipt?.memory_addr).map((receipt) => receipt.memory_addr));
1358
+ const artifacts = normalizeContextPacks(args);
1359
+ const benchmarkSummary = args.benchmarkSummary ?? args.benchmark_summary ?? null;
1360
+ const connectorSummary = args.connectorSummary ?? args.connector_summary ?? null;
1361
+ const replicas = args.replicas ?? null;
1362
+ const connectorReplayWindowHours = connectorSummary?.tombstone_replay_window_hours ?? connectorSummary?.tombstoneReplayWindowHours ?? 0;
1363
+ const latestAnchorBatchRef = args.latest_anchor_batch_ref ?? args.latestAnchorBatchRef ?? null;
1364
+
1365
+ const freshness = computeFreshness(records, policy, nowMs);
1366
+ const duplicateRate = computeDuplicateRate(records, policy);
1367
+ const tombstoneRisk = computeTombstoneRisk({ vault, tombstoneSet, deleteReceiptAddrs, artifacts, connectorReplayWindowHours, policy });
1368
+ const staleDerivedArtifacts = computeStaleDerivedArtifacts({ artifacts, currentRoot: currentRoots.active_set_root, nowMs, policy });
1369
+ const retrievalHitRate = computeRetrievalHitRate({ benchmarkSummary, policy });
1370
+ const retrievalGuardPassed = retrievalHitRate.status === 'healthy';
1371
+ const contextPackProvided = artifacts.length > 0;
1372
+ const selectedCount = contextPackProvided ? artifacts.reduce((sum, artifact) => sum + artifact.memory_addresses.length, 0) : 0;
1373
+ const tokenReduction = computeTokenReduction({ activeCount: activeAddrs.size, contextPackProvided, selectedCount, retrievalGuardPassed, policy });
1374
+ const connectorHealth = computeConnectorHealth({ connectorSummary, policy });
1375
+ const syncForkRisk = computeSyncForkRisk({ replicas, currentRoot: currentRoots.active_set_root, policy });
1376
+ const receiptCoverage = computeReceiptCoverage({ activeAddrs, receipts, latestAnchorBatchRef, currentRoots, policy });
1377
+
1378
+ const nineMetrics = {
1379
+ freshness,
1380
+ duplicate_rate: duplicateRate,
1381
+ tombstone_risk: tombstoneRisk,
1382
+ stale_derived_artifacts: staleDerivedArtifacts,
1383
+ retrieval_hit_rate: retrievalHitRate,
1384
+ token_reduction: tokenReduction,
1385
+ receipt_coverage: receiptCoverage,
1386
+ connector_health: connectorHealth,
1387
+ sync_fork_risk: syncForkRisk,
1388
+ };
1389
+
1390
+ const privacyBoundaries = {
1391
+ private_payloads_included: false,
1392
+ connector_bodies_included: false,
1393
+ identity_labels_included: false,
1394
+ secret_material_included: false,
1395
+ provider_bodies_included: false,
1396
+ };
1397
+
1398
+ const claimBoundaries = {
1399
+ description: 'Local operational SMART-style health evidence computed from public-safe counters, roots, receipt metadata, tombstones, and derived/context-pack refs only.',
1400
+ excludes: [
1401
+ 'Does not prove provider deletion or model forgetting.',
1402
+ 'Does not certify compliance.',
1403
+ 'Does not prove live-chain settlement or a submitted transaction.',
1404
+ 'Does not include plaintext payloads, prompts, connector bodies, identity labels, or secret material.',
1405
+ ],
1406
+ };
1407
+
1408
+ const artifactPublicSummaries = artifacts.map((artifact) => ({
1409
+ artifact_type: artifact.artifact_type,
1410
+ source_root: artifact.source_root,
1411
+ memory_addresses: artifact.memory_addresses,
1412
+ generated_at: artifact.generated_at,
1413
+ }));
1414
+ const reportProxy = {
1415
+ schema: MEMORY_DRIVE_HEALTH_SCHEMA,
1416
+ metrics: nineMetrics,
1417
+ privacy_boundaries: privacyBoundaries,
1418
+ claim_boundaries: claimBoundaries,
1419
+ };
1420
+ const scanInputs = [reportProxy, ...artifactPublicSummaries];
1421
+ if (benchmarkSummary) scanInputs.push(benchmarkSummary);
1422
+ if (connectorSummary) scanInputs.push(connectorSummary);
1423
+ const leakageScan = computeLeakageScan({ reportBody: reportProxy, scanInputs });
1424
+
1425
+ const metrics = { ...nineMetrics, leakage_scan: leakageScan };
1426
+
1427
+ let totalWeight = 0;
1428
+ let weightedSum = 0;
1429
+ for (const name of HEALTH_METRIC_NAMES) {
1430
+ const metric = metrics[name];
1431
+ const weight = HEALTH_METRIC_WEIGHTS[name] ?? 0;
1432
+ weightedSum += metric.score * weight;
1433
+ totalWeight += weight;
1434
+ }
1435
+ const weightedAverage = totalWeight > 0 ? weightedSum / totalWeight : 0;
1436
+ const statuses = HEALTH_METRIC_NAMES.map((name) => metrics[name].status);
1437
+ const hasCritical = statuses.includes('critical');
1438
+ const hasDegraded = statuses.includes('degraded');
1439
+ let overallScore = weightedAverage;
1440
+ if (hasCritical) overallScore = Math.min(overallScore, 49);
1441
+ else if (hasDegraded) overallScore = Math.min(overallScore, 70);
1442
+ overallScore = Math.round(overallScore);
1443
+ const overallStatus = statusFromScore(overallScore);
1444
+
1445
+ const sourceRoot = `memory_root_${currentRoots.active_set_root}`;
1446
+ const driveRef = `drive_${healthDigest({ vault_id: identity.vault_id, tenant_id: identity.tenant_id, subject_id: identity.subject_id })}`;
1447
+ const namespaceRef = `namespace_${healthDigest({ tenant_id: identity.tenant_id, subject_id: identity.subject_id, policy_id: identity.policy_id })}`;
1448
+ const policyRef = `memory_health_policy_${healthDigest(policy)}`;
1449
+
1450
+ const recommendedActions = [];
1451
+ for (const name of HEALTH_METRIC_NAMES) {
1452
+ for (const action of metrics[name].recommended_actions) {
1453
+ if (!recommendedActions.includes(action)) recommendedActions.push(action);
1454
+ }
1455
+ }
1456
+ if (recommendedActions.length === 0) recommendedActions.push('Keep normal monitoring cadence.');
1457
+
1458
+ const connectorCount = connectorSummary ? nonNegativeInt(connectorSummary.connector_count ?? connectorSummary.connectorCount) : 0;
1459
+
1460
+ const blockingReasons = [];
1461
+ if (leakageScan.status !== 'healthy') blockingReasons.push('leakage_scan.status is not healthy');
1462
+ if (tombstoneRisk.status === 'critical') blockingReasons.push('tombstone_risk.status is critical');
1463
+ if (syncForkRisk.status === 'critical') blockingReasons.push('sync_fork_risk.status is critical');
1464
+ if (staleDerivedArtifacts.status === 'critical' || staleDerivedArtifacts.status === 'degraded') blockingReasons.push(`stale_derived_artifacts.status is ${staleDerivedArtifacts.status}`);
1465
+ if (receiptCoverage.status === 'critical') blockingReasons.push('receipt_coverage.status is critical');
1466
+ if (retrievalHitRate.status === 'critical') blockingReasons.push('retrieval_hit_rate.status is critical');
1467
+ const eligibleForAnchorBatch = blockingReasons.length === 0;
1468
+
1469
+ const reportCore = {
1470
+ schema: MEMORY_DRIVE_HEALTH_SCHEMA,
1471
+ created_at: createdAt,
1472
+ drive_ref: driveRef,
1473
+ namespace_ref: namespaceRef,
1474
+ source_root: sourceRoot,
1475
+ policy_ref: policyRef,
1476
+ overall_status: overallStatus,
1477
+ overall_score: overallScore,
1478
+ transaction_submitted: false,
1479
+ raw_memory_on_chain: false,
1480
+ privacy_boundaries: privacyBoundaries,
1481
+ roots: { active_set_root: currentRoots.active_set_root, receipt_log_root: currentRoots.receipt_log_root },
1482
+ metrics,
1483
+ recommended_actions: recommendedActions,
1484
+ claim_boundaries: claimBoundaries,
1485
+ proof_network_ready: {
1486
+ eligible_for_anchor_batch: eligibleForAnchorBatch,
1487
+ blocking_reasons: [...new Set(blockingReasons)],
1488
+ public_payload_only: true,
1489
+ suggested_anchor_fields: {
1490
+ artifact_type: 'memory_drive_health_report',
1491
+ artifact_schema: MEMORY_DRIVE_HEALTH_SCHEMA,
1492
+ source_root: sourceRoot,
1493
+ counts: {
1494
+ active_ref_count: activeAddrs.size,
1495
+ scanned_artifact_count: scanInputs.length,
1496
+ connector_count: connectorCount,
1497
+ },
1498
+ },
1499
+ },
1500
+ };
1501
+
1502
+ const reportRef = `health_report_${healthDigest(reportCore)}`;
1503
+ reportCore.report_ref = reportRef;
1504
+ reportCore.proof_network_ready.suggested_anchor_fields.artifact_root = reportRef;
1505
+ return reportCore;
1506
+ }