monora-ai 2.1.0 → 2.1.3

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 (184) hide show
  1. package/README.md +333 -159
  2. package/dist/aims_governance.d.ts +238 -0
  3. package/dist/aims_governance.d.ts.map +1 -0
  4. package/dist/aims_governance.js +922 -0
  5. package/dist/alerts.d.ts +16 -0
  6. package/dist/alerts.d.ts.map +1 -1
  7. package/dist/alerts.js +16 -0
  8. package/dist/api.d.ts +6 -0
  9. package/dist/api.d.ts.map +1 -1
  10. package/dist/api.js +6 -0
  11. package/dist/assessment.d.ts +85 -0
  12. package/dist/assessment.d.ts.map +1 -1
  13. package/dist/assessment.js +506 -13
  14. package/dist/attribution.d.ts +44 -3
  15. package/dist/attribution.d.ts.map +1 -1
  16. package/dist/attribution.js +197 -10
  17. package/dist/autodetect.d.ts +68 -0
  18. package/dist/autodetect.d.ts.map +1 -1
  19. package/dist/autodetect.js +639 -0
  20. package/dist/bias.d.ts +130 -0
  21. package/dist/bias.d.ts.map +1 -0
  22. package/dist/bias.js +223 -0
  23. package/dist/cli/diagnostics.d.ts +5 -1
  24. package/dist/cli/diagnostics.d.ts.map +1 -1
  25. package/dist/cli/diagnostics.js +23 -6
  26. package/dist/cli/doctor.d.ts +25 -0
  27. package/dist/cli/doctor.d.ts.map +1 -0
  28. package/dist/cli/doctor.js +381 -0
  29. package/dist/cli/fix.d.ts +16 -0
  30. package/dist/cli/fix.d.ts.map +1 -0
  31. package/dist/cli/fix.js +284 -0
  32. package/dist/cli/init.d.ts +57 -0
  33. package/dist/cli/init.d.ts.map +1 -0
  34. package/dist/cli/init.js +205 -0
  35. package/dist/cli.js +1550 -176
  36. package/dist/complianceTargets.d.ts +111 -0
  37. package/dist/complianceTargets.d.ts.map +1 -0
  38. package/dist/complianceTargets.js +521 -0
  39. package/dist/config.d.ts +261 -16
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +381 -32
  42. package/dist/config_migrations.d.ts.map +1 -1
  43. package/dist/config_migrations.js +38 -1
  44. package/dist/config_schema.d.ts +2490 -1035
  45. package/dist/config_schema.d.ts.map +1 -1
  46. package/dist/config_schema.js +233 -64
  47. package/dist/context.d.ts +34 -0
  48. package/dist/context.d.ts.map +1 -1
  49. package/dist/context.js +118 -7
  50. package/dist/control_backbone.d.ts +122 -0
  51. package/dist/control_backbone.d.ts.map +1 -0
  52. package/dist/control_backbone.js +698 -0
  53. package/dist/data-governance.d.ts +187 -0
  54. package/dist/data-governance.d.ts.map +1 -0
  55. package/dist/data-governance.js +424 -0
  56. package/dist/dataResidency.d.ts +44 -0
  57. package/dist/dataResidency.d.ts.map +1 -0
  58. package/dist/dataResidency.js +203 -0
  59. package/dist/dispatcher.d.ts.map +1 -1
  60. package/dist/dispatcher.js +17 -5
  61. package/dist/evidence_store.d.ts +103 -0
  62. package/dist/evidence_store.d.ts.map +1 -0
  63. package/dist/evidence_store.js +459 -0
  64. package/dist/executiveSummary.d.ts +15 -0
  65. package/dist/executiveSummary.d.ts.map +1 -1
  66. package/dist/executiveSummary.js +135 -22
  67. package/dist/identity.d.ts +143 -0
  68. package/dist/identity.d.ts.map +1 -0
  69. package/dist/identity.js +231 -0
  70. package/dist/impact-assessment.d.ts +350 -0
  71. package/dist/impact-assessment.d.ts.map +1 -0
  72. package/dist/impact-assessment.js +580 -0
  73. package/dist/index.d.ts +20 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +247 -5
  76. package/dist/instrumentation.d.ts +1 -1
  77. package/dist/instrumentation.d.ts.map +1 -1
  78. package/dist/instrumentation.js +123 -22
  79. package/dist/integrations/anthropic.d.ts +3 -0
  80. package/dist/integrations/anthropic.d.ts.map +1 -1
  81. package/dist/integrations/anthropic.js +282 -80
  82. package/dist/integrations/governance.d.ts +33 -0
  83. package/dist/integrations/governance.d.ts.map +1 -0
  84. package/dist/integrations/governance.js +208 -0
  85. package/dist/integrations/langchain.d.ts +4 -0
  86. package/dist/integrations/langchain.d.ts.map +1 -1
  87. package/dist/integrations/langchain.js +362 -142
  88. package/dist/integrations/openai.d.ts +9 -0
  89. package/dist/integrations/openai.d.ts.map +1 -1
  90. package/dist/integrations/openai.js +673 -73
  91. package/dist/iso42001_consolidation.d.ts +16 -0
  92. package/dist/iso42001_consolidation.d.ts.map +1 -0
  93. package/dist/iso42001_consolidation.js +413 -0
  94. package/dist/iso42001_workflows.d.ts +263 -0
  95. package/dist/iso42001_workflows.d.ts.map +1 -0
  96. package/dist/iso42001_workflows.js +781 -0
  97. package/dist/lifecycle.d.ts +299 -0
  98. package/dist/lifecycle.d.ts.map +1 -0
  99. package/dist/lifecycle.js +624 -0
  100. package/dist/lineage.d.ts +2 -2
  101. package/dist/lineage.d.ts.map +1 -1
  102. package/dist/lineage.js +9 -16
  103. package/dist/middleware/express.d.ts.map +1 -1
  104. package/dist/middleware/express.js +18 -3
  105. package/dist/middleware/nextjs.js +2 -2
  106. package/dist/model.d.ts +143 -0
  107. package/dist/model.d.ts.map +1 -0
  108. package/dist/model.js +371 -0
  109. package/dist/onboarding.d.ts +42 -0
  110. package/dist/onboarding.d.ts.map +1 -0
  111. package/dist/onboarding.js +1022 -0
  112. package/dist/oversight.d.ts +264 -0
  113. package/dist/oversight.d.ts.map +1 -0
  114. package/dist/oversight.js +497 -0
  115. package/dist/presets.js +7 -7
  116. package/dist/quotas.d.ts +171 -0
  117. package/dist/quotas.d.ts.map +1 -0
  118. package/dist/quotas.js +259 -0
  119. package/dist/register.d.ts +13 -0
  120. package/dist/register.d.ts.map +1 -0
  121. package/dist/register.js +99 -0
  122. package/dist/registry.d.ts +1 -0
  123. package/dist/registry.d.ts.map +1 -1
  124. package/dist/registry.js +7 -0
  125. package/dist/registryData.json +43 -6
  126. package/dist/report.d.ts +2 -1
  127. package/dist/report.d.ts.map +1 -1
  128. package/dist/report.js +189 -2
  129. package/dist/reporting.d.ts +125 -0
  130. package/dist/reporting.d.ts.map +1 -1
  131. package/dist/reporting.js +192 -2
  132. package/dist/resources.d.ts +285 -0
  133. package/dist/resources.d.ts.map +1 -0
  134. package/dist/resources.js +643 -0
  135. package/dist/risk.d.ts +120 -0
  136. package/dist/risk.d.ts.map +1 -0
  137. package/dist/risk.js +220 -0
  138. package/dist/runtime.d.ts +73 -0
  139. package/dist/runtime.d.ts.map +1 -1
  140. package/dist/runtime.js +415 -18
  141. package/dist/schemaInference.d.ts +92 -0
  142. package/dist/schemaInference.d.ts.map +1 -0
  143. package/dist/schemaInference.js +466 -0
  144. package/dist/schema_validation.js +2 -2
  145. package/dist/schemas/config.schema.json +118 -4
  146. package/dist/security_report.js +4 -4
  147. package/dist/signing.d.ts +1 -1
  148. package/dist/signing.d.ts.map +1 -1
  149. package/dist/signing.js +4 -0
  150. package/dist/sinks/file.d.ts +19 -1
  151. package/dist/sinks/file.d.ts.map +1 -1
  152. package/dist/sinks/file.js +82 -13
  153. package/dist/sinks/https.d.ts +10 -0
  154. package/dist/sinks/https.d.ts.map +1 -1
  155. package/dist/sinks/https.js +76 -16
  156. package/dist/sinks/stdout.d.ts +1 -0
  157. package/dist/sinks/stdout.d.ts.map +1 -1
  158. package/dist/sinks/stdout.js +12 -1
  159. package/dist/spec.d.ts +159 -0
  160. package/dist/spec.d.ts.map +1 -0
  161. package/dist/spec.js +391 -0
  162. package/dist/stakeholders.d.ts +199 -0
  163. package/dist/stakeholders.d.ts.map +1 -0
  164. package/dist/stakeholders.js +398 -0
  165. package/dist/standards.d.ts.map +1 -1
  166. package/dist/standards.js +160 -2
  167. package/dist/standards_ingest.d.ts.map +1 -1
  168. package/dist/standards_ingest.js +1 -4
  169. package/dist/telemetry.d.ts +16 -2
  170. package/dist/telemetry.d.ts.map +1 -1
  171. package/dist/telemetry.js +77 -14
  172. package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
  173. package/dist/traced_emitter.d.ts.map +1 -1
  174. package/dist/traced_emitter.js +19 -9
  175. package/dist/trust_package.d.ts +19 -1
  176. package/dist/trust_package.d.ts.map +1 -1
  177. package/dist/trust_package.js +89 -2
  178. package/dist/verify.d.ts.map +1 -1
  179. package/dist/verify.js +9 -2
  180. package/dist/wal.d.ts.map +1 -1
  181. package/dist/wal.js +2 -1
  182. package/package.json +14 -1
  183. package/scripts/postinstall.js +105 -210
  184. package/templates/controls/iso42001_control_catalog.json +1443 -0
@@ -0,0 +1,1022 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildModelSpec = buildModelSpec;
37
+ exports.validateOnboarding = validateOnboarding;
38
+ exports.completeOnboarding = completeOnboarding;
39
+ exports.getOnboardingStatus = getOnboardingStatus;
40
+ exports.resolveEnrichmentPlan = resolveEnrichmentPlan;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const yaml = __importStar(require("js-yaml"));
44
+ const config_1 = require("./config");
45
+ const report_1 = require("./report");
46
+ const standards_1 = require("./standards");
47
+ const runtime_1 = require("./runtime");
48
+ const VALID_STATUSES = new Set(['draft', 'validated', 'completed']);
49
+ const RECOMMENDED_BUNDLES = [
50
+ 'core_observability',
51
+ 'soc2_access',
52
+ 'gdpr_privacy',
53
+ 'iso27001_security',
54
+ ];
55
+ const BUNDLE_SETTINGS = {
56
+ core_observability: {
57
+ 'tracing.emit_span_events': true,
58
+ 'immutability.enabled': true,
59
+ 'immutability.verify_on_emit': true,
60
+ 'policies.enforce': true,
61
+ 'registry.allow_unknown': false,
62
+ },
63
+ soc2_access: {
64
+ 'identity.enabled': true,
65
+ 'identity.require_user_id': true,
66
+ 'policies.enforce': true,
67
+ },
68
+ gdpr_privacy: {
69
+ 'data_handling.enabled': true,
70
+ 'data_handling.mode': 'redact',
71
+ 'data_governance.enabled': true,
72
+ },
73
+ iso27001_security: {
74
+ 'signing.enabled': true,
75
+ 'wal.enabled': true,
76
+ 'wal.sync_mode': 'fsync',
77
+ 'immutability.verify_on_emit': true,
78
+ 'reporting.include_security_report': true,
79
+ },
80
+ };
81
+ const TOGGLE_SETTINGS = {
82
+ identity_tracking: { 'identity.enabled': true },
83
+ risk_tracking: { 'risk_register.enabled': true },
84
+ bias_tracking: { 'bias.enabled': true },
85
+ oversight_tracking: { 'human_oversight.enabled': true },
86
+ data_governance_tracking: { 'data_governance.enabled': true },
87
+ lifecycle_tracking: { 'lifecycle.enabled': true },
88
+ };
89
+ function buildModelSpec(options = {}) {
90
+ const roles = options.roles || {};
91
+ return {
92
+ name: options.name || 'monora_default',
93
+ version: options.version || 'v1',
94
+ event_ts_field: options.eventTsField || 'timestamp',
95
+ schema_ref: options.schemaRef || './onboarding/schema_contract.json',
96
+ roles: {
97
+ inputs: (roles.inputs || []).map(String).filter(Boolean),
98
+ outputs: (roles.outputs || []).map(String).filter(Boolean),
99
+ metadata: (roles.metadata || []).map(String).filter(Boolean),
100
+ identifiers: (roles.identifiers || ['event_id', 'trace_id', 'span_id']).map(String).filter(Boolean),
101
+ },
102
+ };
103
+ }
104
+ function validateOnboarding(options = {}) {
105
+ const { configPath, configDict, inputPathOverride, persist = true } = options;
106
+ const { config, baseDir } = loadWithBaseDir(configPath, configDict);
107
+ ensureOnboardingDefaults(config);
108
+ const enrichmentPlan = resolveEnrichmentPlan(config, { apply: false });
109
+ const onboarding = (config.onboarding || {});
110
+ const modelSpec = (config.model_spec || {});
111
+ const artifactsCfg = (onboarding.artifacts || {});
112
+ const validationCfg = (onboarding.validation || {});
113
+ const errors = [];
114
+ const warnings = [];
115
+ const logsPathRaw = inputPathOverride ||
116
+ String(artifactsCfg.production_logs_path || './monora_events.jsonl');
117
+ const schemaPathRaw = String(artifactsCfg.schema_contract_path || modelSpec.schema_ref || './onboarding/schema_contract.json');
118
+ const datasetSampleRaw = artifactsCfg.dataset_sample_path;
119
+ const baselineReportsRaw = String(artifactsCfg.baseline_reports_dir || './monora_reports/onboarding');
120
+ const logsPath = resolvePath(baseDir, logsPathRaw);
121
+ const schemaPath = resolvePath(baseDir, schemaPathRaw);
122
+ const datasetSamplePath = datasetSampleRaw ? resolvePath(baseDir, String(datasetSampleRaw)) : null;
123
+ const baselineReportsDir = resolvePath(baseDir, baselineReportsRaw);
124
+ const artifacts = {
125
+ production_logs_path: logsPath,
126
+ schema_contract_path: schemaPath,
127
+ dataset_sample_path: datasetSamplePath,
128
+ baseline_reports_dir: baselineReportsDir,
129
+ validation_report_path: path.join(baselineReportsDir, 'onboarding_validation.json'),
130
+ };
131
+ const schemaContract = loadSchemaContract(schemaPath, errors);
132
+ const roles = loadRoles(modelSpec, schemaContract);
133
+ validateRoles(roles, errors);
134
+ const events = loadEvents(logsPath, errors);
135
+ const minRecords = Number(validationCfg.min_log_records ?? 100);
136
+ if (events.length < minRecords) {
137
+ errors.push(`Insufficient production log records: found ${events.length}, required ${minRecords}`);
138
+ }
139
+ let datasetSampleEvents = [];
140
+ if (datasetSamplePath) {
141
+ if (!fs.existsSync(datasetSamplePath)) {
142
+ warnings.push(`Dataset sample path does not exist: ${datasetSamplePath}`);
143
+ }
144
+ else {
145
+ datasetSampleEvents = loadEvents(datasetSamplePath, warnings, true);
146
+ artifacts.dataset_sample_records = datasetSampleEvents.length;
147
+ }
148
+ }
149
+ const coverage = {
150
+ records: events.length,
151
+ dataset_sample_records: Number(artifacts.dataset_sample_records || 0),
152
+ required_field_presence_threshold: Number(validationCfg.required_field_presence_threshold ?? 0.95),
153
+ type_conformance_threshold: Number(validationCfg.type_conformance_threshold ?? 0.90),
154
+ field_presence: {},
155
+ field_type_conformance: {},
156
+ enrichment_plan: enrichmentPlan,
157
+ profiling: {},
158
+ inference: {},
159
+ };
160
+ const mappedFields = mappedFieldsFromRoles(roles);
161
+ const schema = extractSchemaObject(schemaContract);
162
+ if (!schema || Object.keys(schema).length === 0) {
163
+ errors.push('Schema contract missing JSON schema object.');
164
+ }
165
+ if (events.length > 0 && mappedFields.length > 0) {
166
+ const fieldCoverage = computeFieldCoverage(events, mappedFields, schema || {});
167
+ coverage.field_presence = fieldCoverage.presence;
168
+ coverage.field_type_conformance = fieldCoverage.typeConformance;
169
+ const presenceThreshold = Number(validationCfg.required_field_presence_threshold ?? 0.95);
170
+ const typeThreshold = Number(validationCfg.type_conformance_threshold ?? 0.90);
171
+ for (const [field, ratio] of Object.entries(fieldCoverage.presence)) {
172
+ const numberRatio = Number(ratio);
173
+ if (numberRatio < presenceThreshold) {
174
+ errors.push(`Field '${field}' presence ${numberRatio.toFixed(3)} is below threshold ${presenceThreshold.toFixed(3)}`);
175
+ }
176
+ }
177
+ for (const [field, ratio] of Object.entries(fieldCoverage.typeConformance)) {
178
+ const numberRatio = Number(ratio);
179
+ if (numberRatio < typeThreshold) {
180
+ errors.push(`Field '${field}' type conformance ${numberRatio.toFixed(3)} is below threshold ${typeThreshold.toFixed(3)}`);
181
+ }
182
+ }
183
+ }
184
+ const profileFields = collectProfileFields(mappedFields, schema || {});
185
+ const logsProfile = buildEventProfile(events, profileFields);
186
+ const datasetProfile = buildEventProfile(datasetSampleEvents, profileFields);
187
+ const inference = buildInferenceSummary({
188
+ roles,
189
+ fieldProfiles: logsProfile.field_profiles || {},
190
+ mappedFields,
191
+ preferredTsField: typeof modelSpec.event_ts_field === 'string' ? modelSpec.event_ts_field : null,
192
+ });
193
+ coverage.profiling = {
194
+ production_logs: logsProfile,
195
+ dataset_sample: datasetProfile,
196
+ };
197
+ coverage.inference = inference;
198
+ const status = errors.length === 0 ? 'validated' : 'failed';
199
+ const result = {
200
+ status,
201
+ errors,
202
+ warnings,
203
+ coverage,
204
+ artifacts,
205
+ };
206
+ fs.mkdirSync(path.dirname(artifacts.validation_report_path), { recursive: true });
207
+ fs.writeFileSync(artifacts.validation_report_path, JSON.stringify(result, null, 2), 'utf-8');
208
+ if (status === 'validated') {
209
+ onboarding.status = 'validated';
210
+ onboarding.completion = onboarding.completion || {};
211
+ onboarding.completion.last_validated_at = nowIso();
212
+ emitOnboardingEvent('onboarding_validated', {
213
+ status,
214
+ errors: errors.length,
215
+ warnings: warnings.length,
216
+ records: events.length,
217
+ });
218
+ }
219
+ else if (!VALID_STATUSES.has(String(onboarding.status || '').toLowerCase())) {
220
+ onboarding.status = 'draft';
221
+ }
222
+ if (persist) {
223
+ persistConfig(configPath, config);
224
+ }
225
+ return result;
226
+ }
227
+ function completeOnboarding(options = {}) {
228
+ const { configPath, configDict, completedBy } = options;
229
+ const { config, baseDir } = loadWithBaseDir(configPath, configDict);
230
+ ensureOnboardingDefaults(config);
231
+ const validation = validateOnboarding({
232
+ configPath,
233
+ configDict: config,
234
+ persist: false,
235
+ });
236
+ const errors = [...validation.errors];
237
+ const warnings = [...validation.warnings];
238
+ const coverage = validation.coverage || {};
239
+ const artifacts = { ...(validation.artifacts || {}) };
240
+ if (errors.length > 0) {
241
+ return {
242
+ status: 'failed',
243
+ errors,
244
+ warnings,
245
+ coverage,
246
+ artifacts,
247
+ };
248
+ }
249
+ const onboarding = (config.onboarding || {});
250
+ let standards = Array.isArray(onboarding.standards) ? onboarding.standards : ['SOC2', 'GDPR', 'ISO27001'];
251
+ standards = standards.map((value) => String(value).toUpperCase()).filter(Boolean);
252
+ if (standards.length === 0) {
253
+ standards = ['SOC2', 'GDPR', 'ISO27001'];
254
+ }
255
+ onboarding.standards = standards;
256
+ const logsPath = String(artifacts.production_logs_path || resolvePath(baseDir, './monora_events.jsonl'));
257
+ const events = loadEvents(logsPath, errors);
258
+ const baselineDir = String(artifacts.baseline_reports_dir || resolvePath(baseDir, './monora_reports/onboarding'));
259
+ fs.mkdirSync(baselineDir, { recursive: true });
260
+ const generatedReports = [];
261
+ for (const standard of standards) {
262
+ const templatePath = resolveTemplatePath(standard);
263
+ if (!templatePath) {
264
+ warnings.push(`No bundled template available for standard: ${standard}`);
265
+ continue;
266
+ }
267
+ try {
268
+ const report = (0, standards_1.buildStandardsReport)({
269
+ events,
270
+ config,
271
+ reportPath: undefined,
272
+ claimsPath: templatePath,
273
+ });
274
+ const reportPath = path.join(baselineDir, `${standard.toLowerCase()}_baseline_report.json`);
275
+ fs.writeFileSync(reportPath, JSON.stringify(report, null, 2), 'utf-8');
276
+ generatedReports.push({
277
+ standard,
278
+ report_path: reportPath,
279
+ coverage_summary: report.coverage_summary || {},
280
+ excerpts_summary: report.excerpts_summary || {},
281
+ findings_summary: report.findings_summary || {},
282
+ });
283
+ emitOnboardingEvent('baseline_report_generated', {
284
+ standard,
285
+ report_path: reportPath,
286
+ coverage_summary: report.coverage_summary || {},
287
+ findings_summary: report.findings_summary || {},
288
+ });
289
+ }
290
+ catch (error) {
291
+ errors.push(`Failed to generate baseline report for ${standard}: ${error?.message || error}`);
292
+ }
293
+ }
294
+ const status = errors.length > 0 ? 'failed' : 'completed';
295
+ if (status === 'completed') {
296
+ onboarding.status = 'completed';
297
+ onboarding.completion = onboarding.completion || {};
298
+ onboarding.completion.completed_at = nowIso();
299
+ onboarding.completion.completed_by = completedBy || onboarding.completion.completed_by || null;
300
+ onboarding.completion.last_validated_at = onboarding.completion.last_validated_at || nowIso();
301
+ emitOnboardingEvent('onboarding_completed', {
302
+ standards,
303
+ reports_generated: generatedReports.length,
304
+ completed_by: completedBy || null,
305
+ });
306
+ }
307
+ const summaryPath = path.join(baselineDir, 'onboarding_summary.json');
308
+ const summary = {
309
+ status,
310
+ generated_at: nowIso(),
311
+ standards,
312
+ reports: generatedReports,
313
+ validation: {
314
+ coverage,
315
+ errors,
316
+ warnings,
317
+ },
318
+ };
319
+ fs.writeFileSync(summaryPath, JSON.stringify(summary, null, 2), 'utf-8');
320
+ artifacts.baseline_reports = generatedReports;
321
+ artifacts.onboarding_summary_path = summaryPath;
322
+ persistConfig(configPath, config);
323
+ return {
324
+ status,
325
+ errors,
326
+ warnings,
327
+ coverage,
328
+ artifacts,
329
+ };
330
+ }
331
+ function getOnboardingStatus(options = {}) {
332
+ const { configPath, configDict } = options;
333
+ const { config, baseDir } = loadWithBaseDir(configPath, configDict);
334
+ ensureOnboardingDefaults(config);
335
+ const onboarding = (config.onboarding || {});
336
+ const artifacts = (onboarding.artifacts || {});
337
+ const modelSpec = (config.model_spec || {});
338
+ const roles = (modelSpec.roles || {});
339
+ const missing = [];
340
+ const logsPathRaw = artifacts.production_logs_path ? String(artifacts.production_logs_path) : '';
341
+ const schemaPathRaw = artifacts.schema_contract_path ? String(artifacts.schema_contract_path) : '';
342
+ const baselineDirRaw = artifacts.baseline_reports_dir
343
+ ? String(artifacts.baseline_reports_dir)
344
+ : './monora_reports/onboarding';
345
+ const logsPath = logsPathRaw ? resolvePath(baseDir, logsPathRaw) : '';
346
+ const schemaPath = schemaPathRaw ? resolvePath(baseDir, schemaPathRaw) : '';
347
+ const baselineDir = resolvePath(baseDir, baselineDirRaw);
348
+ if (!logsPath) {
349
+ missing.push('onboarding.artifacts.production_logs_path');
350
+ }
351
+ else if (!fs.existsSync(logsPath)) {
352
+ missing.push(`production logs file not found: ${logsPath}`);
353
+ }
354
+ if (!schemaPath) {
355
+ missing.push('onboarding.artifacts.schema_contract_path');
356
+ }
357
+ else if (!fs.existsSync(schemaPath)) {
358
+ missing.push(`schema contract file not found: ${schemaPath}`);
359
+ }
360
+ if (!Array.isArray(roles.inputs) || roles.inputs.length === 0) {
361
+ missing.push('model_spec.roles.inputs');
362
+ }
363
+ if (!Array.isArray(roles.outputs) || roles.outputs.length === 0) {
364
+ missing.push('model_spec.roles.outputs');
365
+ }
366
+ const generatedReports = [];
367
+ if (fs.existsSync(baselineDir) && fs.statSync(baselineDir).isDirectory()) {
368
+ for (const filename of fs.readdirSync(baselineDir).sort()) {
369
+ if (filename.endsWith('_baseline_report.json')) {
370
+ generatedReports.push(path.join(baselineDir, filename));
371
+ }
372
+ }
373
+ }
374
+ const validationReportPath = path.join(baselineDir, 'onboarding_validation.json');
375
+ const summaryPath = path.join(baselineDir, 'onboarding_summary.json');
376
+ const enrichmentPlan = resolveEnrichmentPlan(config, { apply: false });
377
+ return {
378
+ status: onboarding.status || 'draft',
379
+ enabled: Boolean(onboarding.enabled),
380
+ required_in_production: Boolean(onboarding.required_in_production),
381
+ standards: onboarding.standards || [],
382
+ artifacts: {
383
+ ...artifacts,
384
+ production_logs_path: logsPath,
385
+ schema_contract_path: schemaPath,
386
+ baseline_reports_dir: baselineDir,
387
+ },
388
+ generated_artifacts: {
389
+ validation_report_path: fs.existsSync(validationReportPath) ? validationReportPath : null,
390
+ onboarding_summary_path: fs.existsSync(summaryPath) ? summaryPath : null,
391
+ baseline_reports: generatedReports,
392
+ },
393
+ enrichment_plan: enrichmentPlan,
394
+ missing_requirements: missing,
395
+ };
396
+ }
397
+ function resolveEnrichmentPlan(config, options) {
398
+ ensureOnboardingDefaults(config);
399
+ const apply = options?.apply === true;
400
+ const enrichments = (config.enrichments || {});
401
+ const bundlesRaw = Array.isArray(enrichments.bundles) ? enrichments.bundles : RECOMMENDED_BUNDLES;
402
+ const bundles = bundlesRaw.map((value) => String(value).trim()).filter(Boolean);
403
+ const togglesRaw = enrichments.toggles && typeof enrichments.toggles === 'object'
404
+ ? enrichments.toggles
405
+ : {};
406
+ const settings = {};
407
+ const unknownBundles = [];
408
+ const appliedCapabilities = [];
409
+ for (const bundle of bundles) {
410
+ const patch = BUNDLE_SETTINGS[bundle];
411
+ if (!patch) {
412
+ unknownBundles.push(bundle);
413
+ continue;
414
+ }
415
+ Object.assign(settings, patch);
416
+ appliedCapabilities.push(bundle);
417
+ }
418
+ const toggleStates = {};
419
+ for (const [toggleName, patch] of Object.entries(TOGGLE_SETTINGS)) {
420
+ const enabled = Boolean(togglesRaw[toggleName] ?? true);
421
+ toggleStates[toggleName] = enabled;
422
+ if (enabled) {
423
+ Object.assign(settings, patch);
424
+ }
425
+ else {
426
+ for (const settingPath of Object.keys(patch)) {
427
+ if (settingPath.endsWith('.enabled')) {
428
+ settings[settingPath] = false;
429
+ }
430
+ }
431
+ }
432
+ }
433
+ let currentSettings = {};
434
+ for (const key of Object.keys(settings)) {
435
+ currentSettings[key] = getConfigPath(config, key);
436
+ }
437
+ if (apply) {
438
+ for (const [settingPath, settingValue] of Object.entries(settings)) {
439
+ setConfigPath(config, settingPath, settingValue);
440
+ }
441
+ currentSettings = {};
442
+ for (const key of Object.keys(settings)) {
443
+ currentSettings[key] = getConfigPath(config, key);
444
+ }
445
+ }
446
+ const unappliedSettings = Object.entries(settings)
447
+ .filter(([key, value]) => currentSettings[key] !== value)
448
+ .map(([key]) => key);
449
+ return {
450
+ bundles,
451
+ unknown_bundles: unknownBundles,
452
+ toggle_states: toggleStates,
453
+ applied_capabilities: appliedCapabilities,
454
+ target_settings: settings,
455
+ current_settings: currentSettings,
456
+ unapplied_settings: unappliedSettings,
457
+ };
458
+ }
459
+ function loadWithBaseDir(configPath, configDict) {
460
+ const config = (0, config_1.loadConfig)({ configPath, configDict });
461
+ const baseDir = configPath ? path.dirname(path.resolve(configPath)) : process.cwd();
462
+ return { config, baseDir };
463
+ }
464
+ function ensureOnboardingDefaults(config) {
465
+ const defaults = config_1.DEFAULT_CONFIG;
466
+ config.onboarding = mergeSection(defaults.onboarding || {}, config.onboarding || {});
467
+ config.model_spec = mergeSection(defaults.model_spec || {}, config.model_spec || {});
468
+ config.enrichments = mergeSection(defaults.enrichments || {}, config.enrichments || {});
469
+ }
470
+ function mergeSection(base, override) {
471
+ const result = { ...base };
472
+ for (const [key, value] of Object.entries(override || {})) {
473
+ if (key in result &&
474
+ value &&
475
+ typeof value === 'object' &&
476
+ !Array.isArray(value) &&
477
+ result[key] &&
478
+ typeof result[key] === 'object' &&
479
+ !Array.isArray(result[key])) {
480
+ result[key] = mergeSection(result[key], value);
481
+ }
482
+ else {
483
+ result[key] = value;
484
+ }
485
+ }
486
+ return result;
487
+ }
488
+ function persistConfig(configPath, config) {
489
+ if (!configPath) {
490
+ return;
491
+ }
492
+ fs.mkdirSync(path.dirname(path.resolve(configPath)), { recursive: true });
493
+ if (configPath.endsWith('.json')) {
494
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
495
+ return;
496
+ }
497
+ const serialized = yaml.dump(config, { sortKeys: false });
498
+ fs.writeFileSync(configPath, serialized, 'utf-8');
499
+ }
500
+ function resolvePath(baseDir, value) {
501
+ if (path.isAbsolute(value)) {
502
+ return value;
503
+ }
504
+ return path.resolve(baseDir, value);
505
+ }
506
+ function loadSchemaContract(schemaPath, errors) {
507
+ if (!fs.existsSync(schemaPath)) {
508
+ errors.push(`Schema contract not found: ${schemaPath}`);
509
+ return {};
510
+ }
511
+ try {
512
+ const raw = fs.readFileSync(schemaPath, 'utf-8');
513
+ const payload = JSON.parse(raw);
514
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
515
+ errors.push(`Schema contract must be a JSON object: ${schemaPath}`);
516
+ return {};
517
+ }
518
+ return payload;
519
+ }
520
+ catch (error) {
521
+ errors.push(`Failed to read schema contract ${schemaPath}: ${error?.message || error}`);
522
+ return {};
523
+ }
524
+ }
525
+ function extractSchemaObject(contract) {
526
+ if (!contract || typeof contract !== 'object')
527
+ return {};
528
+ if (contract.schema && typeof contract.schema === 'object' && !Array.isArray(contract.schema)) {
529
+ return contract.schema;
530
+ }
531
+ if (contract.type || contract.properties) {
532
+ return contract;
533
+ }
534
+ return {};
535
+ }
536
+ function loadRoles(modelSpec, schemaContract) {
537
+ const roles = {
538
+ inputs: [],
539
+ outputs: [],
540
+ metadata: [],
541
+ identifiers: [],
542
+ };
543
+ const modelRoles = modelSpec.roles && typeof modelSpec.roles === 'object' ? modelSpec.roles : {};
544
+ const schemaRoles = schemaContract.roles && typeof schemaContract.roles === 'object'
545
+ ? schemaContract.roles
546
+ : {};
547
+ for (const key of Object.keys(roles)) {
548
+ const value = Array.isArray(modelRoles[key])
549
+ ? modelRoles[key]
550
+ : Array.isArray(schemaRoles[key])
551
+ ? schemaRoles[key]
552
+ : [];
553
+ roles[key] = value.map((item) => String(item).trim()).filter(Boolean);
554
+ }
555
+ return roles;
556
+ }
557
+ function validateRoles(roles, errors) {
558
+ if (!roles.inputs || roles.inputs.length === 0) {
559
+ errors.push('Model spec role mapping missing required inputs.');
560
+ }
561
+ if (!roles.outputs || roles.outputs.length === 0) {
562
+ errors.push('Model spec role mapping missing required outputs.');
563
+ }
564
+ if (!roles.metadata || roles.metadata.length === 0) {
565
+ errors.push('Model spec role mapping missing metadata fields.');
566
+ }
567
+ if (!roles.identifiers || roles.identifiers.length === 0) {
568
+ errors.push('Model spec role mapping missing identifiers.');
569
+ }
570
+ }
571
+ function mappedFieldsFromRoles(roles) {
572
+ const fields = [];
573
+ for (const key of ['inputs', 'outputs', 'metadata', 'identifiers']) {
574
+ for (const field of roles[key] || []) {
575
+ if (!fields.includes(field)) {
576
+ fields.push(field);
577
+ }
578
+ }
579
+ }
580
+ return fields;
581
+ }
582
+ function loadEvents(filePath, messages, warnOnly = false) {
583
+ if (!fs.existsSync(filePath)) {
584
+ messages.push(`Production log file not found: ${filePath}`);
585
+ return [];
586
+ }
587
+ try {
588
+ return (0, report_1.loadJsonl)(filePath);
589
+ }
590
+ catch (error) {
591
+ messages.push(`${warnOnly ? 'Warning' : 'Error'} loading events ${filePath}: ${error?.message || error}`);
592
+ return [];
593
+ }
594
+ }
595
+ function computeFieldCoverage(events, mappedFields, schema) {
596
+ const presence = {};
597
+ const typeConformance = {};
598
+ for (const field of mappedFields) {
599
+ let found = 0;
600
+ let typedOk = 0;
601
+ const expectedType = schemaTypeForField(schema, field);
602
+ for (const event of events) {
603
+ const [exists, value] = resolveField(event, field);
604
+ if (!exists)
605
+ continue;
606
+ found += 1;
607
+ if (!expectedType || matchesType(value, expectedType)) {
608
+ typedOk += 1;
609
+ }
610
+ }
611
+ presence[field] = events.length > 0 ? found / events.length : 0;
612
+ typeConformance[field] = found > 0 ? typedOk / found : 0;
613
+ }
614
+ return { presence, typeConformance };
615
+ }
616
+ function resolveField(event, field) {
617
+ const normalized = field.startsWith('$.') ? field.slice(2) : field;
618
+ if (normalized.startsWith('body.')) {
619
+ return dig(event.body, normalized.split('.').slice(1));
620
+ }
621
+ const top = dig(event, normalized.split('.'));
622
+ if (top[0]) {
623
+ return top;
624
+ }
625
+ return dig(event.body, normalized.split('.'));
626
+ }
627
+ function dig(value, parts) {
628
+ let cursor = value;
629
+ for (const part of parts) {
630
+ if (cursor && typeof cursor === 'object' && part in cursor) {
631
+ cursor = cursor[part];
632
+ continue;
633
+ }
634
+ return [false, null];
635
+ }
636
+ return [true, cursor];
637
+ }
638
+ function schemaTypeForField(schema, field) {
639
+ if (!schema || typeof schema !== 'object')
640
+ return null;
641
+ const fields = schema.fields;
642
+ if (fields && typeof fields === 'object') {
643
+ const fieldInfo = fields[field];
644
+ if (typeof fieldInfo === 'string')
645
+ return fieldInfo;
646
+ if (fieldInfo && typeof fieldInfo === 'object' && typeof fieldInfo.type === 'string') {
647
+ return fieldInfo.type;
648
+ }
649
+ }
650
+ let normalized = field;
651
+ if (normalized.startsWith('$.'))
652
+ normalized = normalized.slice(2);
653
+ if (normalized.startsWith('body.'))
654
+ normalized = normalized.slice(5);
655
+ const parts = normalized.split('.');
656
+ let cursor = schema;
657
+ for (let idx = 0; idx < parts.length; idx += 1) {
658
+ const part = parts[idx];
659
+ const properties = cursor?.properties;
660
+ if (!properties || typeof properties !== 'object' || !(part in properties)) {
661
+ return null;
662
+ }
663
+ const node = properties[part];
664
+ if (idx === parts.length - 1) {
665
+ return typeof node?.type === 'string' ? node.type : null;
666
+ }
667
+ cursor = node;
668
+ }
669
+ return null;
670
+ }
671
+ function matchesType(value, expectedType) {
672
+ const expected = String(expectedType).toLowerCase();
673
+ if (expected === 'string')
674
+ return typeof value === 'string';
675
+ if (expected === 'number' || expected === 'float')
676
+ return typeof value === 'number' && !Number.isNaN(value);
677
+ if (expected === 'integer' || expected === 'int')
678
+ return Number.isInteger(value);
679
+ if (expected === 'boolean' || expected === 'bool')
680
+ return typeof value === 'boolean';
681
+ if (expected === 'object')
682
+ return !!value && typeof value === 'object' && !Array.isArray(value);
683
+ if (expected === 'array')
684
+ return Array.isArray(value);
685
+ if (expected === 'null')
686
+ return value === null;
687
+ return true;
688
+ }
689
+ function resolveTemplatePath(standard) {
690
+ const mapping = {
691
+ SOC2: 'soc2_claims.json',
692
+ GDPR: 'gdpr_claims.json',
693
+ ISO27001: 'iso27001_claims.json',
694
+ ISO: 'iso27001_claims.json',
695
+ };
696
+ const filename = mapping[String(standard).toUpperCase().trim()];
697
+ if (!filename)
698
+ return null;
699
+ const candidates = [
700
+ path.resolve(__dirname, '..', 'templates', 'standards', filename),
701
+ path.resolve(process.cwd(), 'templates', 'standards', filename),
702
+ path.resolve(process.cwd(), 'monora-node', 'templates', 'standards', filename),
703
+ ];
704
+ for (const candidate of candidates) {
705
+ if (fs.existsSync(candidate)) {
706
+ return candidate;
707
+ }
708
+ }
709
+ return null;
710
+ }
711
+ function collectProfileFields(mappedFields, schema) {
712
+ const fields = [];
713
+ for (const field of mappedFields) {
714
+ if (!fields.includes(field)) {
715
+ fields.push(field);
716
+ }
717
+ }
718
+ for (const field of schemaFieldCandidates(schema)) {
719
+ if (!fields.includes(field)) {
720
+ fields.push(field);
721
+ }
722
+ }
723
+ for (const field of ['event_id', 'trace_id', 'span_id', 'event_type', 'timestamp', 'service_name']) {
724
+ if (!fields.includes(field)) {
725
+ fields.push(field);
726
+ }
727
+ }
728
+ return fields.slice(0, 80);
729
+ }
730
+ function schemaFieldCandidates(schema, options) {
731
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
732
+ return [];
733
+ }
734
+ const prefix = options?.prefix || '';
735
+ const depth = options?.depth || 0;
736
+ const maxDepth = options?.maxDepth ?? 5;
737
+ if (depth > maxDepth) {
738
+ return [];
739
+ }
740
+ const fields = [];
741
+ const explicitFields = schema.fields;
742
+ if (explicitFields && typeof explicitFields === 'object' && !Array.isArray(explicitFields)) {
743
+ for (const key of Object.keys(explicitFields)) {
744
+ const field = String(key).trim();
745
+ if (field && !fields.includes(field)) {
746
+ fields.push(field);
747
+ }
748
+ }
749
+ }
750
+ const properties = schema.properties;
751
+ if (properties && typeof properties === 'object' && !Array.isArray(properties)) {
752
+ for (const [key, child] of Object.entries(properties)) {
753
+ const part = String(key).trim();
754
+ if (!part)
755
+ continue;
756
+ const currentPath = prefix ? `${prefix}.${part}` : part;
757
+ if (!fields.includes(currentPath)) {
758
+ fields.push(currentPath);
759
+ }
760
+ const nested = schemaFieldCandidates(child && typeof child === 'object' && !Array.isArray(child) ? child : {}, { prefix: currentPath, depth: depth + 1, maxDepth });
761
+ for (const nestedField of nested) {
762
+ if (!fields.includes(nestedField)) {
763
+ fields.push(nestedField);
764
+ }
765
+ }
766
+ }
767
+ }
768
+ return fields;
769
+ }
770
+ function buildEventProfile(events, fields, options) {
771
+ const maxRecords = options?.maxRecords ?? 5000;
772
+ const sampleLimit = options?.sampleLimit ?? 3;
773
+ const maxDistinct = options?.maxDistinct ?? 200;
774
+ const profiledEvents = events.slice(0, maxRecords);
775
+ const total = profiledEvents.length;
776
+ const fieldProfiles = {};
777
+ for (const field of fields) {
778
+ let presentCount = 0;
779
+ let nullCount = 0;
780
+ const types = {};
781
+ const samples = [];
782
+ const distinctValues = new Set();
783
+ let minValue = null;
784
+ let maxValue = null;
785
+ let minLength = null;
786
+ let maxLength = null;
787
+ for (const event of profiledEvents) {
788
+ const [exists, value] = resolveField(event, field);
789
+ if (!exists)
790
+ continue;
791
+ presentCount += 1;
792
+ if (value === null) {
793
+ nullCount += 1;
794
+ }
795
+ const runtimeType = inferRuntimeType(value);
796
+ types[runtimeType] = (types[runtimeType] || 0) + 1;
797
+ if (samples.length < sampleLimit) {
798
+ const rendered = renderSample(value);
799
+ if (!samples.includes(rendered)) {
800
+ samples.push(rendered);
801
+ }
802
+ }
803
+ if (distinctValues.size < maxDistinct) {
804
+ distinctValues.add(stableValueRepr(value));
805
+ }
806
+ if (runtimeType === 'integer' || runtimeType === 'number') {
807
+ const numeric = Number(value);
808
+ if (Number.isFinite(numeric)) {
809
+ minValue = minValue === null ? numeric : Math.min(minValue, numeric);
810
+ maxValue = maxValue === null ? numeric : Math.max(maxValue, numeric);
811
+ }
812
+ }
813
+ else if (runtimeType === 'string') {
814
+ const valueLength = String(value).length;
815
+ minLength = minLength === null ? valueLength : Math.min(minLength, valueLength);
816
+ maxLength = maxLength === null ? valueLength : Math.max(maxLength, valueLength);
817
+ }
818
+ }
819
+ const presenceRatio = total > 0 ? presentCount / total : 0;
820
+ const profile = {
821
+ presence_ratio: Number(presenceRatio.toFixed(6)),
822
+ present_count: presentCount,
823
+ null_count: nullCount,
824
+ distinct_count: distinctValues.size,
825
+ types: Object.fromEntries(Object.entries(types).sort((a, b) => a[0].localeCompare(b[0]))),
826
+ sample_values: samples,
827
+ };
828
+ if (minValue !== null) {
829
+ profile.min = minValue;
830
+ }
831
+ if (maxValue !== null) {
832
+ profile.max = maxValue;
833
+ }
834
+ if (minLength !== null) {
835
+ profile.min_length = minLength;
836
+ }
837
+ if (maxLength !== null) {
838
+ profile.max_length = maxLength;
839
+ }
840
+ fieldProfiles[field] = profile;
841
+ }
842
+ return {
843
+ records_profiled: total,
844
+ records_truncated: events.length > maxRecords,
845
+ field_profiles: fieldProfiles,
846
+ };
847
+ }
848
+ function buildInferenceSummary(options) {
849
+ const { roles, fieldProfiles, mappedFields, preferredTsField } = options;
850
+ const suggestedRoles = suggestRoles(fieldProfiles);
851
+ const monitorableFields = Object.entries(fieldProfiles)
852
+ .filter(([, profile]) => Number(profile.presence_ratio || 0) >= 0.5)
853
+ .map(([field]) => field)
854
+ .sort();
855
+ const schemaMappingGaps = mappedFields
856
+ .filter((field) => Number((fieldProfiles[field] || {}).presence_ratio || 0) <= 0)
857
+ .sort();
858
+ return {
859
+ current_roles: roles,
860
+ suggested_roles: suggestedRoles,
861
+ suggested_event_ts_field: suggestEventTsField(fieldProfiles, preferredTsField),
862
+ monitorable_fields: monitorableFields,
863
+ schema_mapping_gaps: schemaMappingGaps,
864
+ };
865
+ }
866
+ function suggestRoles(fieldProfiles) {
867
+ const entries = Object.entries(fieldProfiles).sort((a, b) => {
868
+ const left = Number(a[1].presence_ratio || 0);
869
+ const right = Number(b[1].presence_ratio || 0);
870
+ if (right !== left) {
871
+ return right - left;
872
+ }
873
+ return a[0].localeCompare(b[0]);
874
+ });
875
+ const suggestions = {
876
+ inputs: [],
877
+ outputs: [],
878
+ metadata: [],
879
+ identifiers: [],
880
+ };
881
+ for (const [field, profile] of entries) {
882
+ if (Number(profile.presence_ratio || 0) <= 0) {
883
+ continue;
884
+ }
885
+ const lowered = field.toLowerCase();
886
+ if (/(prompt|question|query|input|request)/.test(lowered)) {
887
+ suggestions.inputs.push(field);
888
+ }
889
+ if (/(response|answer|completion|output|result)/.test(lowered)) {
890
+ suggestions.outputs.push(field);
891
+ }
892
+ if (/(timestamp|time|date|event_type|service|model|status|purpose)/.test(lowered)) {
893
+ suggestions.metadata.push(field);
894
+ }
895
+ if (lowered.endsWith('_id') ||
896
+ ['event_id', 'trace_id', 'span_id', 'session_id', 'user_id', 'request_id'].includes(lowered)) {
897
+ suggestions.identifiers.push(field);
898
+ }
899
+ }
900
+ return {
901
+ inputs: Array.from(new Set(suggestions.inputs)).slice(0, 12),
902
+ outputs: Array.from(new Set(suggestions.outputs)).slice(0, 12),
903
+ metadata: Array.from(new Set(suggestions.metadata)).slice(0, 12),
904
+ identifiers: Array.from(new Set(suggestions.identifiers)).slice(0, 12),
905
+ };
906
+ }
907
+ function suggestEventTsField(fieldProfiles, preferred) {
908
+ if (preferred && fieldProfiles[preferred]) {
909
+ return preferred;
910
+ }
911
+ const candidates = [];
912
+ for (const [field, profile] of Object.entries(fieldProfiles)) {
913
+ const lowered = field.toLowerCase();
914
+ if (!lowered.includes('time') && !lowered.includes('date')) {
915
+ continue;
916
+ }
917
+ const types = profile.types;
918
+ if (!types || typeof types !== 'object') {
919
+ continue;
920
+ }
921
+ if (!('string' in types) && !('number' in types) && !('integer' in types)) {
922
+ continue;
923
+ }
924
+ candidates.push({
925
+ field,
926
+ presence: Number(profile.presence_ratio || 0),
927
+ });
928
+ }
929
+ if (candidates.length === 0) {
930
+ return null;
931
+ }
932
+ candidates.sort((a, b) => {
933
+ if (b.presence !== a.presence) {
934
+ return b.presence - a.presence;
935
+ }
936
+ return a.field.localeCompare(b.field);
937
+ });
938
+ return candidates[0].field;
939
+ }
940
+ function inferRuntimeType(value) {
941
+ if (value === null || value === undefined)
942
+ return 'null';
943
+ if (typeof value === 'boolean')
944
+ return 'boolean';
945
+ if (Number.isInteger(value))
946
+ return 'integer';
947
+ if (typeof value === 'number')
948
+ return 'number';
949
+ if (typeof value === 'string')
950
+ return 'string';
951
+ if (Array.isArray(value))
952
+ return 'array';
953
+ if (typeof value === 'object')
954
+ return 'object';
955
+ return typeof value;
956
+ }
957
+ function stableValueRepr(value) {
958
+ if (Array.isArray(value) || (value && typeof value === 'object')) {
959
+ try {
960
+ return JSON.stringify(value);
961
+ }
962
+ catch {
963
+ return String(value);
964
+ }
965
+ }
966
+ return String(value);
967
+ }
968
+ function renderSample(value, maxLength = 160) {
969
+ if (typeof value === 'string') {
970
+ return value.length <= maxLength ? value : `${value.slice(0, maxLength - 3)}...`;
971
+ }
972
+ if (typeof value === 'number' || typeof value === 'boolean' || value === null) {
973
+ return value;
974
+ }
975
+ if (Array.isArray(value) || (value && typeof value === 'object')) {
976
+ const rendered = stableValueRepr(value);
977
+ return rendered.length <= maxLength ? rendered : `${rendered.slice(0, maxLength - 3)}...`;
978
+ }
979
+ return String(value);
980
+ }
981
+ function setConfigPath(config, dottedPath, value) {
982
+ const parts = String(dottedPath).split('.').filter(Boolean);
983
+ if (parts.length === 0)
984
+ return;
985
+ let cursor = config;
986
+ for (const part of parts.slice(0, -1)) {
987
+ if (!cursor[part] || typeof cursor[part] !== 'object' || Array.isArray(cursor[part])) {
988
+ cursor[part] = {};
989
+ }
990
+ cursor = cursor[part];
991
+ }
992
+ cursor[parts[parts.length - 1]] = value;
993
+ }
994
+ function getConfigPath(config, dottedPath) {
995
+ const parts = String(dottedPath).split('.').filter(Boolean);
996
+ let cursor = config;
997
+ for (const part of parts) {
998
+ if (!cursor || typeof cursor !== 'object' || !(part in cursor)) {
999
+ return null;
1000
+ }
1001
+ cursor = cursor[part];
1002
+ }
1003
+ return cursor;
1004
+ }
1005
+ function emitOnboardingEvent(eventType, body) {
1006
+ try {
1007
+ const state = (0, runtime_1.getState)();
1008
+ if (state && typeof state.emitInternal === 'function') {
1009
+ state.emitInternal({
1010
+ event_type: eventType,
1011
+ body,
1012
+ purpose: 'governance',
1013
+ });
1014
+ }
1015
+ }
1016
+ catch {
1017
+ // no-op
1018
+ }
1019
+ }
1020
+ function nowIso() {
1021
+ return new Date().toISOString();
1022
+ }