@thinkingai/ae-cli 6.1.23 → 6.1.25
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.
- package/README.md +7 -1
- package/README.zh.md +7 -1
- package/dist/{auth-XZNXFRJS.js → auth-LHM7NQPR.js} +167 -7
- package/dist/{capability-FYTU3X6L.js → capability-SJI5KOCK.js} +11 -6
- package/dist/{chunk-CCS66K4K.js → chunk-2FJM4HRV.js} +3 -3
- package/dist/{chunk-57RRFUEZ.js → chunk-5XRQ3CZR.js} +4 -4
- package/dist/{chunk-EQ255HKO.js → chunk-7WZACOAI.js} +2 -2
- package/dist/{chunk-DX5CDO34.js → chunk-BW7JUDEI.js} +84 -19
- package/dist/{chunk-7XGFSUOM.js → chunk-DU72X2IO.js} +271 -76
- package/dist/{chunk-V2NUHPXF.js → chunk-GK7WDY7E.js} +1 -1
- package/dist/{chunk-7FTTULED.js → chunk-IG3DYEIR.js} +4 -1
- package/dist/{chunk-HBGADCKA.js → chunk-KJDOTPYU.js} +3 -3
- package/dist/{chunk-4NRCTUZJ.js → chunk-KS4DE3MX.js} +4 -4
- package/dist/{chunk-JOCDD4ON.js → chunk-N4BLPJC7.js} +1 -1
- package/dist/{chunk-HFGZGYCG.js → chunk-QYXDJOLA.js} +252 -6
- package/dist/{chunk-DVMLWQD4.js → chunk-SO5LKIWP.js} +2 -2
- package/dist/{chunk-VYXXOKYS.js → chunk-XKIW3QMF.js} +7 -4
- package/dist/{chunk-MAPZ7VB6.js → chunk-YVGXGTD6.js} +13 -0
- package/dist/{community-report-client-CU22W53K.js → community-report-client-6VJDDMJJ.js} +1 -1
- package/dist/{config-XO3LI3SA.js → config-XQWOPDHN.js} +25 -6
- package/dist/{context-IFJI3LIT.js → context-M3HDGEIR.js} +4 -4
- package/dist/{data-integration-HNGUKFIC.js → data-integration-XBTCGXQT.js} +6 -6
- package/dist/index.js +78 -41
- package/dist/{local-data-upload-client-GTRIT64F.js → local-data-upload-client-3P7NIVQ4.js} +1 -1
- package/dist/{memory-QGPSNCQS.js → memory-6APEB2JB.js} +4 -4
- package/dist/{metadata-DI5BMYFU.js → metadata-JRYKNUS5.js} +7 -7
- package/dist/{model-RNPQXIBI.js → model-ZS7HVGKN.js} +4 -4
- package/dist/{personal-semantic-preference-5C3WUXFI.js → personal-semantic-preference-IDE2GE5T.js} +8 -6
- package/dist/project-semantic-36KOCYN7.js +356 -0
- package/dist/{sync-O45NXEQY.js → sync-EQLSTUS7.js} +7 -7
- package/dist/{te-agent-K5MSPNHJ.js → te-agent-Z3HCTKR7.js} +348 -55
- package/dist/{te-analysis-AISWCOOZ.js → te-analysis-5ZZ6YHVH.js} +940 -144
- package/dist/{te-community-4OYU3BDA.js → te-community-Z7JACGF3.js} +3 -3
- package/dist/{te-dataops-NFIPB6FX.js → te-dataops-F7GQOIS6.js} +644 -276
- package/dist/{te-engage-BAM3GBFX.js → te-engage-RNRMYDO3.js} +6 -6
- package/dist/{te-experiment-GUTZXZ5Z.js → te-experiment-BTAC2UNK.js} +6 -6
- package/dist/{te-kb-3TS73NO6.js → te-kb-QJLJEX5K.js} +323 -181
- package/dist/{te-system-STMHLS5J.js → te-system-IXC43QHZ.js} +6 -6
- package/dist/{te-team-3I5AOX3N.js → te-team-BIZIKIHZ.js} +6 -6
- package/dist/{update-RZXLPCRH.js → update-W2SGQNKT.js} +4 -4
- package/package.json +11 -4
- package/skills/ae-agent/SKILL.md +9 -4
- package/skills/ae-agent/references/notification.md +40 -0
- package/skills/ae-analysis/SKILL.md +44 -21
- package/skills/ae-analysis/references/adhoc_export.md +1 -1
- package/skills/ae-analysis/references/adhoc_run.md +1 -1
- package/skills/ae-analysis/references/agent_review_submit_to_page.md +3 -1
- package/skills/ae-analysis/references/ai_models/event.md +6 -1
- package/skills/ae-analysis/references/ai_models/funnel.md +7 -1
- package/skills/ae-analysis/references/ai_models/heat_map.md +23 -0
- package/skills/ae-analysis/references/ai_models/interval.md +24 -0
- package/skills/ae-analysis/references/ai_models/path.md +20 -0
- package/skills/ae-analysis/references/ai_models/prop_analysis.md +2 -0
- package/skills/ae-analysis/references/ai_models/rank_list.md +30 -0
- package/skills/ae-analysis/references/ai_models/retention.md +45 -1
- package/skills/ae-analysis/references/ai_models/revenue.md +20 -2
- package/skills/ae-analysis/references/ai_models/session.md +76 -0
- package/skills/ae-analysis/references/ai_models/tag.md +2 -0
- package/skills/ae-analysis/references/ai_models.md +76 -6
- package/skills/ae-analysis/references/analysis_data_retrieval.md +4 -0
- package/skills/ae-analysis/references/analysis_drilldown_contract.md +4 -1
- package/skills/ae-analysis/references/asset_batch_info_export.md +10 -0
- package/skills/ae-analysis/references/asset_batch_sql_export.md +13 -1
- package/skills/ae-analysis/references/asset_export.md +12 -1
- package/skills/ae-analysis/references/asset_list.md +1 -0
- package/skills/ae-analysis/references/asset_search.md +11 -5
- package/skills/ae-analysis/references/bi_panel_list.md +1 -1
- package/skills/ae-analysis/references/catalog_list.md +1 -1
- package/skills/ae-analysis/references/collaboration.md +48 -0
- package/skills/ae-analysis/references/command_index.md +19 -17
- package/skills/ae-analysis/references/dashboard_list.md +4 -4
- package/skills/ae-analysis/references/dashboard_report_data_export.md +2 -0
- package/skills/ae-analysis/references/drilldown_session_details_run.md +41 -0
- package/skills/ae-analysis/references/event_export.md +3 -1
- package/skills/ae-analysis/references/governance_recommendation_auto_review.md +77 -0
- package/skills/ae-analysis/references/governance_recommendation_export.md +11 -0
- package/skills/ae-analysis/references/metadata_resolution.md +3 -3
- package/skills/ae-analysis/references/metric_export.md +3 -1
- package/skills/ae-analysis/references/metric_list.md +1 -1
- package/skills/ae-analysis/references/operation_record_export.md +10 -0
- package/skills/ae-analysis/references/personal_semantic_preference_add.md +2 -2
- package/skills/ae-analysis/references/personal_semantic_preference_get.md +4 -4
- package/skills/ae-analysis/references/personal_semantic_preference_list.md +4 -4
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki.md +30 -12
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +59 -0
- package/skills/ae-analysis/references/property_export.md +3 -1
- package/skills/ae-analysis/references/report_create.md +5 -1
- package/skills/ae-analysis/references/report_data_export.md +6 -0
- package/skills/ae-analysis/references/report_get.md +2 -0
- package/skills/ae-analysis/references/report_list.md +5 -5
- package/skills/ae-analysis/references/report_update.md +7 -1
- package/skills/ae-analysis/references/sql_table_columns.md +4 -4
- package/skills/ae-analysis/references/sql_table_list.md +5 -5
- package/skills/ae-analysis/references/user_cluster_models.md +8 -0
- package/skills/ae-analysis/references/user_tag_create.md +7 -1
- package/skills/ae-analysis/references/user_tag_get.md +1 -1
- package/skills/ae-analysis/references/user_tag_models.md +18 -2
- package/skills/ae-analysis/references/user_tag_refresh.md +1 -1
- package/skills/ae-analysis/references/user_tag_update.md +2 -2
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +337 -12
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-rules.md +8 -3
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +284 -24
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/package-wiki-source-zip.mjs +185 -22
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/precompiled-source.mjs +46 -2
- package/skills/ae-capability/SKILL.md +63 -1
- package/skills/ae-capability/references/collaboration.md +48 -0
- package/skills/ae-community/SKILL.md +5 -1
- package/skills/ae-community/references/collaboration.md +48 -0
- package/skills/ae-data-integration/SKILL.md +4 -0
- package/skills/ae-data-integration/references/collaboration.md +48 -0
- package/skills/ae-data-integration-helper/references/cpp_server_sdk_faq.md +2 -2
- package/skills/ae-data-integration-helper/references/logbus2_parser_plugin.md +6 -6
- package/skills/ae-data-integration-helper/references/sdk_log_guide.md +4 -4
- package/skills/ae-dataops/SKILL.md +54 -74
- package/skills/ae-dataops/references/collaboration.md +48 -0
- package/skills/ae-dataops/references/dataops-backfill.md +23 -18
- package/skills/ae-dataops/references/dataops-flow-create.md +74 -23
- package/skills/ae-dataops/references/dataops-flow-monitor.md +45 -13
- package/skills/ae-dataops/references/dataops-integration.md +57 -30
- package/skills/ae-dataops/references/dataops-query.md +21 -4
- package/skills/ae-dataops/references/dataops-table.md +143 -11
- package/skills/ae-engage/SKILL.md +21 -6
- package/skills/ae-engage/references/add-channel.md +3 -3
- package/skills/ae-engage/references/channel-mgmt.md +3 -3
- package/skills/ae-engage/references/collaboration.md +48 -0
- package/skills/ae-engage/references/common-metric.md +2 -2
- package/skills/ae-engage/references/save-task.md +2 -2
- package/skills/ae-engage/references/scene-config-channel.md +4 -4
- package/skills/ae-generate-tracking-code/SKILL.md +1 -1
- package/skills/ae-generate-tracking-plan/SKILL.md +4 -0
- package/skills/ae-generate-tracking-plan/references/collaboration.md +48 -0
- package/skills/ae-kb/SKILL.md +9 -1
- package/skills/ae-kb/references/collaboration.md +48 -0
- package/skills/ae-kb/references/schema-import.md +30 -0
- package/skills/ae-kb-discovery/SKILL.md +7 -2
- package/skills/ae-kb-discovery/references/collaboration.md +48 -0
- package/skills/ae-metadata/SKILL.md +20 -12
- package/skills/ae-metadata/references/collaboration.md +48 -0
- package/dist/project-semantic-3LF6Q6JZ.js +0 -1119
- package/skills/ae-project-semantic/SKILL.md +0 -193
- package/skills/ae-project-semantic/references/query-routing-v5.md +0 -165
- package/skills/ae-project-semantic/references/recommendation-quality.md +0 -68
|
@@ -11,6 +11,7 @@ const outputRoot = path.resolve(requiredArg(args, 'output'));
|
|
|
11
11
|
const force = Boolean(args.force);
|
|
12
12
|
const allowTruncated = Boolean(args['allow-truncated']);
|
|
13
13
|
const allowAllVisible = Boolean(args['allow-all-visible']);
|
|
14
|
+
const allowSemanticPlanSnapshotDrift = Boolean(args['allow-semantic-plan-snapshot-drift']);
|
|
14
15
|
|
|
15
16
|
assertSafePaths(packageRoot, outputRoot);
|
|
16
17
|
|
|
@@ -74,6 +75,7 @@ const domainPlan = readObject(domainPlanPath, 'business domain plan');
|
|
|
74
75
|
const classifications = validateAndEnrichDomainPlan(domainPlan);
|
|
75
76
|
const domains = classifications.domains;
|
|
76
77
|
const appendices = classifications.appendices;
|
|
78
|
+
const projectBusinessModel = classifications.project_business_model;
|
|
77
79
|
const domainByDashboardId = new Map();
|
|
78
80
|
for (const domain of domains) {
|
|
79
81
|
for (const id of domain.dashboard_ids) domainByDashboardId.set(id, domain);
|
|
@@ -132,6 +134,7 @@ const corpus = {
|
|
|
132
134
|
truncated: Boolean(descriptor.truncated ?? manifest.truncated),
|
|
133
135
|
business_domain_source: 'agent-authored semantic plan validated against every dashboard in the asset package',
|
|
134
136
|
business_domain_plan_hash: domainPlanHash,
|
|
137
|
+
project_business_model: projectBusinessModel,
|
|
135
138
|
counts: {
|
|
136
139
|
business_domains: domains.length,
|
|
137
140
|
technical_appendices: appendices.length,
|
|
@@ -244,7 +247,7 @@ function validateAndEnrichDomainPlan(plan) {
|
|
|
244
247
|
if (!['1.0', '2.0'].includes(text(plan.schema_version))) {
|
|
245
248
|
fail('Business domain plan schema 1.0 or project semantic Wiki plan schema 2.0 is required.');
|
|
246
249
|
}
|
|
247
|
-
if (text(plan.source_snapshot_hash) !== snapshotHash) {
|
|
250
|
+
if (text(plan.source_snapshot_hash) !== snapshotHash && !allowSemanticPlanSnapshotDrift) {
|
|
248
251
|
fail(`Business domain plan snapshot mismatch: expected ${snapshotHash}.`);
|
|
249
252
|
}
|
|
250
253
|
if (text(plan.generation_method) !== 'agent_semantic_synthesis') {
|
|
@@ -296,6 +299,10 @@ function validateAndEnrichDomainPlan(plan) {
|
|
|
296
299
|
const dashboardRows = dashboardIds.map((dashboardId) => dashboardById.get(dashboardId));
|
|
297
300
|
const sourceContainerRefs = uniqueObjects(dashboardRows.map((row) => object(row.source_container_ref)), 'container_key');
|
|
298
301
|
const reportRefs = uniqueObjects(dashboardRows.flatMap((row) => array(row.report_refs)), 'report_id');
|
|
302
|
+
const reportIds = new Set(reportRefs.map((ref) => text(ref.report_id)).filter(Boolean));
|
|
303
|
+
const metricIds = new Set(reports
|
|
304
|
+
.filter((report) => reportIds.has(text(report.resource_key)))
|
|
305
|
+
.flatMap((report) => array(report.metric_occurrences).map((item) => text(item.metric_key)).filter(Boolean)));
|
|
299
306
|
return {
|
|
300
307
|
domain_id: id,
|
|
301
308
|
title,
|
|
@@ -303,6 +310,8 @@ function validateAndEnrichDomainPlan(plan) {
|
|
|
303
310
|
primary_questions: questions,
|
|
304
311
|
primary_metrics: primaryMetrics,
|
|
305
312
|
drilldown_dimensions: drilldownDimensions,
|
|
313
|
+
domain_judgment_model: normalizeDomainJudgmentModel(domain.domain_judgment_model, id,
|
|
314
|
+
new Set(dashboardIds), reportIds, metricIds),
|
|
306
315
|
merge_rationale: rationale,
|
|
307
316
|
dashboard_ids: dashboardIds,
|
|
308
317
|
dashboard_refs: dashboardRows.map((row) => ({
|
|
@@ -356,17 +365,160 @@ function validateAndEnrichDomainPlan(plan) {
|
|
|
356
365
|
report_refs: uniqueObjects(dashboardRows.flatMap((row) => array(row.report_refs)), 'report_id'),
|
|
357
366
|
};
|
|
358
367
|
});
|
|
368
|
+
const projectBusinessModel = normalizeProjectBusinessModel(plan.project_business_model, domainIds);
|
|
359
369
|
validateSqlSemanticPlan(plan);
|
|
360
370
|
const missing = dashboards.map((row) => text(row.resource_key)).filter((id) => !assigned.has(id));
|
|
361
371
|
if (missing.length) {
|
|
362
372
|
fail(`Business domain plan does not classify ${missing.length} dashboard(s): ${missing.slice(0, 20).join(', ')}${missing.length > 20 ? ', ...' : ''}.`);
|
|
363
373
|
}
|
|
364
374
|
return {
|
|
375
|
+
project_business_model: projectBusinessModel,
|
|
365
376
|
domains: enrichedDomains.sort((a, b) => a.domain_id.localeCompare(b.domain_id, 'en')),
|
|
366
377
|
appendices: enrichedAppendices.sort((a, b) => a.appendix_id.localeCompare(b.appendix_id, 'en')),
|
|
367
378
|
};
|
|
368
379
|
}
|
|
369
380
|
|
|
381
|
+
function normalizeProjectBusinessModel(value, domainIds) {
|
|
382
|
+
const model = object(value);
|
|
383
|
+
const businessPositioning = text(model.business_positioning);
|
|
384
|
+
const audienceRoles = array(model.audience_roles).map(text).filter(Boolean);
|
|
385
|
+
const businessObjects = array(model.business_objects).map((item, index) => {
|
|
386
|
+
const row = object(item);
|
|
387
|
+
const objectId = text(row.object_id);
|
|
388
|
+
const name = text(row.name);
|
|
389
|
+
const meaning = text(row.meaning);
|
|
390
|
+
if (!/^[a-z0-9][a-z0-9_-]{1,79}$/.test(objectId)) fail(`project_business_model.business_objects[${index}] has invalid object_id.`);
|
|
391
|
+
if (!name || !meaning) fail(`project_business_model.business_objects[${index}] requires name and meaning.`);
|
|
392
|
+
const evidenceRefs = normalizePlanAssetRefs(row.evidence_refs, `business object ${objectId}`);
|
|
393
|
+
if (!evidenceRefs.length) fail(`business object ${objectId} requires evidence_refs.`);
|
|
394
|
+
return { object_id: objectId, name, meaning, evidence_refs: evidenceRefs };
|
|
395
|
+
});
|
|
396
|
+
const objectNames = new Set(businessObjects.map((item) => item.name));
|
|
397
|
+
const objectRelationships = array(model.object_relationships).map((item, index) => {
|
|
398
|
+
const row = object(item);
|
|
399
|
+
const fromObject = text(row.from_object);
|
|
400
|
+
const toObject = text(row.to_object);
|
|
401
|
+
const relationship = text(row.relationship);
|
|
402
|
+
if (!fromObject || !toObject || !relationship) {
|
|
403
|
+
fail(`project_business_model.object_relationships[${index}] requires from_object, to_object and relationship.`);
|
|
404
|
+
}
|
|
405
|
+
if (!objectNames.has(fromObject) || !objectNames.has(toObject)) {
|
|
406
|
+
fail(`object relationship ${fromObject || '<empty>'}->${toObject || '<empty>'} must reference declared business object names.`);
|
|
407
|
+
}
|
|
408
|
+
const evidenceRefs = normalizePlanAssetRefs(row.evidence_refs, `object relationship ${fromObject}->${toObject}`);
|
|
409
|
+
if (!evidenceRefs.length) fail(`object relationship ${fromObject}->${toObject} requires evidence_refs.`);
|
|
410
|
+
return { from_object: fromObject, to_object: toObject, relationship, evidence_refs: evidenceRefs };
|
|
411
|
+
});
|
|
412
|
+
const decisionChains = array(model.decision_chains).map((item, index) => {
|
|
413
|
+
const row = object(item);
|
|
414
|
+
const chainId = text(row.chain_id);
|
|
415
|
+
const title = text(row.title);
|
|
416
|
+
const decisionQuestion = text(row.decision_question);
|
|
417
|
+
const signals = array(row.signals).map(text).filter(Boolean);
|
|
418
|
+
const decisionSteps = array(row.decision_steps).map(text).filter(Boolean);
|
|
419
|
+
const preferredDomainIds = array(row.preferred_domain_ids).map(text).filter(Boolean);
|
|
420
|
+
const assetRefs = normalizePlanAssetRefs(row.asset_refs, `decision chain ${chainId || index + 1}`);
|
|
421
|
+
const boundaries = array(row.boundaries).map(text).filter(Boolean);
|
|
422
|
+
if (!/^[a-z0-9][a-z0-9_-]{1,79}$/.test(chainId)) fail(`project_business_model.decision_chains[${index}] has invalid chain_id.`);
|
|
423
|
+
if (!title || !decisionQuestion) fail(`decision chain ${chainId} requires title and decision_question.`);
|
|
424
|
+
if (signals.length < 2) fail(`decision chain ${chainId} requires at least two signals.`);
|
|
425
|
+
if (decisionSteps.length < 2) fail(`decision chain ${chainId} requires at least two decision_steps.`);
|
|
426
|
+
if (!preferredDomainIds.length || preferredDomainIds.some((id) => !domainIds.has(id))) {
|
|
427
|
+
fail(`decision chain ${chainId} must reference existing preferred_domain_ids.`);
|
|
428
|
+
}
|
|
429
|
+
if (!assetRefs.length) fail(`decision chain ${chainId} requires asset_refs.`);
|
|
430
|
+
if (!boundaries.length) fail(`decision chain ${chainId} requires boundaries.`);
|
|
431
|
+
return {
|
|
432
|
+
chain_id: chainId,
|
|
433
|
+
title,
|
|
434
|
+
decision_question: decisionQuestion,
|
|
435
|
+
signals,
|
|
436
|
+
decision_steps: decisionSteps,
|
|
437
|
+
preferred_domain_ids: preferredDomainIds,
|
|
438
|
+
asset_refs: assetRefs,
|
|
439
|
+
requires_live_execution: Boolean(row.requires_live_execution),
|
|
440
|
+
boundaries,
|
|
441
|
+
};
|
|
442
|
+
});
|
|
443
|
+
const nonGoals = array(model.non_goals).map(text).filter(Boolean);
|
|
444
|
+
if (!businessPositioning) fail('project_business_model requires business_positioning.');
|
|
445
|
+
if (!audienceRoles.length) fail('project_business_model requires audience_roles.');
|
|
446
|
+
if (!businessObjects.length) fail('project_business_model requires business_objects.');
|
|
447
|
+
if (!objectRelationships.length) fail('project_business_model requires object_relationships.');
|
|
448
|
+
if (!decisionChains.length) fail('project_business_model requires decision_chains.');
|
|
449
|
+
if (!nonGoals.length) fail('project_business_model requires non_goals.');
|
|
450
|
+
const combined = [
|
|
451
|
+
businessPositioning, ...audienceRoles, ...businessObjects.flatMap((item) => [item.name, item.meaning]),
|
|
452
|
+
...objectRelationships.map((item) => item.relationship),
|
|
453
|
+
...decisionChains.flatMap((item) => [item.title, item.decision_question, ...item.signals, ...item.decision_steps, ...item.boundaries]),
|
|
454
|
+
...nonGoals,
|
|
455
|
+
].join('\n');
|
|
456
|
+
if (isMechanicalPlanText(combined)) fail('project_business_model looks mechanically generated; Agent must author project-level business semantics from current asset evidence.');
|
|
457
|
+
return {
|
|
458
|
+
business_positioning: businessPositioning,
|
|
459
|
+
audience_roles: audienceRoles,
|
|
460
|
+
business_objects: businessObjects,
|
|
461
|
+
object_relationships: objectRelationships,
|
|
462
|
+
decision_chains: decisionChains,
|
|
463
|
+
non_goals: nonGoals,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function normalizeDomainJudgmentModel(value, domainId, domainDashboardIds, domainReportIds, domainMetricIds) {
|
|
468
|
+
const model = object(value);
|
|
469
|
+
const businessStateJudged = text(model.business_state_judged);
|
|
470
|
+
const mainObjects = array(model.main_objects).map(text).filter(Boolean);
|
|
471
|
+
const signals = array(model.signals).map(text).filter(Boolean);
|
|
472
|
+
const decisionPath = array(model.decision_path).map(text).filter(Boolean);
|
|
473
|
+
const boundaries = array(model.boundaries).map(text).filter(Boolean);
|
|
474
|
+
const attachmentLogic = array(model.asset_attachment_logic).map((item, index) => {
|
|
475
|
+
const row = object(item);
|
|
476
|
+
const assetRef = normalizePlanAssetRef(row.asset_ref, `domain ${domainId} asset_attachment_logic[${index}]`);
|
|
477
|
+
const role = text(row.role);
|
|
478
|
+
const reason = text(row.reason);
|
|
479
|
+
if (!['primary_entry', 'supporting_evidence', 'drilldown', 'exclusion'].includes(role)) {
|
|
480
|
+
fail(`domain ${domainId} asset_attachment_logic[${index}] has invalid role.`);
|
|
481
|
+
}
|
|
482
|
+
if (!reason || reason.length < 10) fail(`domain ${domainId} asset_attachment_logic[${index}] requires concrete reason.`);
|
|
483
|
+
const inDomain = assetRef.resource_type === 'dashboard' ? domainDashboardIds.has(assetRef.resource_key)
|
|
484
|
+
: assetRef.resource_type === 'report' ? domainReportIds.has(assetRef.resource_key)
|
|
485
|
+
: assetRef.resource_type === 'metric' ? domainMetricIds.has(assetRef.resource_key) : false;
|
|
486
|
+
if (!inDomain) fail(`domain ${domainId} asset_attachment_logic references ${assetRef.resource_type}:${assetRef.resource_key} outside domain closure.`);
|
|
487
|
+
return { asset_ref: assetRef, role, reason };
|
|
488
|
+
});
|
|
489
|
+
if (!businessStateJudged) fail(`Domain ${domainId} is missing domain_judgment_model.business_state_judged.`);
|
|
490
|
+
if (!mainObjects.length) fail(`Domain ${domainId} is missing domain_judgment_model.main_objects.`);
|
|
491
|
+
if (signals.length < 2) fail(`Domain ${domainId} domain_judgment_model requires at least two signals.`);
|
|
492
|
+
if (decisionPath.length < 2) fail(`Domain ${domainId} domain_judgment_model requires at least two decision_path steps.`);
|
|
493
|
+
if (!attachmentLogic.length) fail(`Domain ${domainId} domain_judgment_model requires asset_attachment_logic.`);
|
|
494
|
+
if (!boundaries.length) fail(`Domain ${domainId} domain_judgment_model requires boundaries.`);
|
|
495
|
+
const combined = [businessStateJudged, ...mainObjects, ...signals, ...decisionPath, ...attachmentLogic.map((item) => item.reason), ...boundaries].join('\n');
|
|
496
|
+
if (isMechanicalPlanText(combined)) fail(`Domain ${domainId} judgment model looks mechanically generated.`);
|
|
497
|
+
return {
|
|
498
|
+
business_state_judged: businessStateJudged,
|
|
499
|
+
main_objects: mainObjects,
|
|
500
|
+
signals,
|
|
501
|
+
decision_path: decisionPath,
|
|
502
|
+
asset_attachment_logic: attachmentLogic,
|
|
503
|
+
boundaries,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function normalizePlanAssetRefs(values, label) {
|
|
508
|
+
return array(values).map((value, index) => normalizePlanAssetRef(value, `${label} evidence_refs[${index}]`));
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function normalizePlanAssetRef(value, label) {
|
|
512
|
+
const ref = object(value);
|
|
513
|
+
const type = text(ref.resource_type);
|
|
514
|
+
const key = text(ref.resource_key);
|
|
515
|
+
const exists = type === 'dashboard' ? dashboardById.has(key)
|
|
516
|
+
: type === 'report' ? reportById.has(key)
|
|
517
|
+
: type === 'metric' ? metrics.some((metric) => text(metric.resource_key) === key) : false;
|
|
518
|
+
if (!exists) fail(`${label} references unknown asset ${type || '<type>'}:${key || '<key>'}.`);
|
|
519
|
+
return { resource_type: type, resource_key: key };
|
|
520
|
+
}
|
|
521
|
+
|
|
370
522
|
|
|
371
523
|
function assertAgentAuthoredDomain(domain, label) {
|
|
372
524
|
const values = [domain.title, domain.summary, domain.merge_rationale, ...array(domain.primary_questions)].map(text);
|
|
@@ -464,7 +616,48 @@ function renderBriefIndex() {
|
|
|
464
616
|
|
|
465
617
|
function renderDomainSource(domain) {
|
|
466
618
|
const key = text(domain.domain_id);
|
|
467
|
-
return `---\ntype: project-business-domain-source\nproject_id: ${projectId}\ndomain_id: ${yaml(key)}\ntitle: ${yaml(domain.title)}\nclassification_method: agent_semantic_synthesis\nsnapshot_hash: ${yaml(snapshotHash)}\n---\n\n# ${heading(domain.title)}\n\n${text(domain.summary)}\n\n## 主要业务问题\n\n${array(domain.primary_questions).map((question) => `- ${question}`).join('\n')}\n\n## 归类依据\n\n${text(domain.merge_rationale)}\n\n${renderDomainAgentUsageSummary(domain)}\n## 看板(${array(domain.dashboard_refs).length})\n\n${refLinks(array(domain.dashboard_refs), 'dashboard_id', 'dashboard_name', dashboardFiles, '../dashboards')}\n\n## 涉及报表(${array(domain.report_refs).length})\n\n${refLinks(array(domain.report_refs), 'report_id', 'report_name', reportFiles, '../reports')}\n\n## 物理来源容器\n\n${containerLinks(domain.source_container_refs, '../source-containers')}\n\n## 规划依据摘要\n\n- Domain ID: \`${key}\`\n- 归类方法: agent_semantic_synthesis\n- 快照: \`${snapshotHash}\`\n- 纳入看板: ${array(domain.dashboard_refs).length}\n- 涉及报表: ${array(domain.report_refs).length}\n- 物理来源容器: ${array(domain.source_container_refs).length}\n`;
|
|
619
|
+
return `---\ntype: project-business-domain-source\nproject_id: ${projectId}\ndomain_id: ${yaml(key)}\ntitle: ${yaml(domain.title)}\nclassification_method: agent_semantic_synthesis\nsnapshot_hash: ${yaml(snapshotHash)}\n---\n\n# ${heading(domain.title)}\n\n${text(domain.summary)}\n\n## 这个域判断什么\n\n${renderDomainJudgmentModel(domain)}\n\n## 主要业务问题\n\n${array(domain.primary_questions).map((question) => `- ${question}`).join('\n')}\n\n## 归类依据\n\n${text(domain.merge_rationale)}\n\n${renderDomainAgentUsageSummary(domain)}\n## 看板(${array(domain.dashboard_refs).length})\n\n${refLinks(array(domain.dashboard_refs), 'dashboard_id', 'dashboard_name', dashboardFiles, '../dashboards')}\n\n## 涉及报表(${array(domain.report_refs).length})\n\n${refLinks(array(domain.report_refs), 'report_id', 'report_name', reportFiles, '../reports')}\n\n## 物理来源容器\n\n${containerLinks(domain.source_container_refs, '../source-containers')}\n\n## 规划依据摘要\n\n- Domain ID: \`${key}\`\n- 归类方法: agent_semantic_synthesis\n- 快照: \`${snapshotHash}\`\n- 纳入看板: ${array(domain.dashboard_refs).length}\n- 涉及报表: ${array(domain.report_refs).length}\n- 物理来源容器: ${array(domain.source_container_refs).length}\n`;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function renderDomainJudgmentModel(domain) {
|
|
623
|
+
const model = object(domain.domain_judgment_model);
|
|
624
|
+
const attachmentLines = array(model.asset_attachment_logic).map((item) => {
|
|
625
|
+
const row = object(item);
|
|
626
|
+
const ref = object(row.asset_ref);
|
|
627
|
+
const label = domainAssetLabel(ref);
|
|
628
|
+
return `- ${domainAttachmentRoleLabel(row.role)}:${label}。${stripClausePunctuation(row.reason)}`;
|
|
629
|
+
});
|
|
630
|
+
return `- 判断状态:${stripClausePunctuation(model.business_state_judged)}\n- 主要对象:${array(model.main_objects).map(text).filter(Boolean).join('、')}\n- 判断信号:${joinChineseClauses(model.signals)}\n- 判断路径:\n${renderNumberedSteps(model.decision_path, ' ')}\n- 资产挂载:\n${attachmentLines.join('\n') || ' - 无'}\n- 边界:${joinChineseClauses(model.boundaries)}`;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function domainAssetLabel(ref) {
|
|
634
|
+
const type = text(ref.resource_type);
|
|
635
|
+
const key = text(ref.resource_key);
|
|
636
|
+
if (type === 'dashboard') {
|
|
637
|
+
const dashboard = dashboardById.get(key);
|
|
638
|
+
const title = text(dashboard?.title) || key;
|
|
639
|
+
return `[${link(title)}](../dashboards/${dashboardFiles.get(key)})(dashboard:${key})`;
|
|
640
|
+
}
|
|
641
|
+
if (type === 'report') {
|
|
642
|
+
const report = reportById.get(key);
|
|
643
|
+
const title = text(report?.title) || key;
|
|
644
|
+
return `[${link(title)}](../reports/${reportFiles.get(key)})(report:${key})`;
|
|
645
|
+
}
|
|
646
|
+
if (type === 'metric') {
|
|
647
|
+
const metric = metrics.find((row) => text(row.resource_key) === key);
|
|
648
|
+
const title = text(metric?.title) || key;
|
|
649
|
+
return `[${link(title)}](../metrics/${metricFiles.get(key)})(metric:${key})`;
|
|
650
|
+
}
|
|
651
|
+
return `${type}:${key}`;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function domainAttachmentRoleLabel(value) {
|
|
655
|
+
return ({
|
|
656
|
+
primary_entry: '首选入口',
|
|
657
|
+
supporting_evidence: '辅助证据',
|
|
658
|
+
drilldown: '下钻资产',
|
|
659
|
+
exclusion: '排除资产',
|
|
660
|
+
})[text(value)] ?? text(value);
|
|
468
661
|
}
|
|
469
662
|
|
|
470
663
|
function renderDomainAgentUsageSummary(domain) {
|
|
@@ -838,7 +1031,7 @@ function renderDashboardAgentUsageSummary(dashboard, reportRows, notes, domain,
|
|
|
838
1031
|
const purposes = reportRows.slice(0, 8).map((row) => reportPurpose(row));
|
|
839
1032
|
const metrics = topDomainFacts(reportRows.flatMap((row) => reportMetricSummaryItems(row)), 10);
|
|
840
1033
|
const dimensions = topDomainFacts(reportRows.flatMap((row) => reportDimensionSummaryItems(row)), 10);
|
|
841
|
-
return `- 用途:${classification}${reportRows.length ? `这张看板承载 ${reportRows.length} 张报表,用于从看板层进入相关分析。` : '当前没有关联报表。'}\n- 适合回答:\n${purposes.map((item) => ` - ${item}`).join('\n') || ' - 当前看板没有足够报表证据概括适用问题。'}\n- 主要指标:${metrics.join('、') || '
|
|
1034
|
+
return `- 用途:${classification}${reportRows.length ? `这张看板承载 ${reportRows.length} 张报表,用于从看板层进入相关分析。` : '当前没有关联报表。'}\n- 适合回答:\n${purposes.map((item) => ` - ${item}`).join('\n') || ' - 当前看板没有足够报表证据概括适用问题。'}\n- 主要指标:${metrics.join('、') || '关联报表没有暴露可稳定概括的指标,使用时需要先进入下属报表核验。'}\n- 常用下钻维度:${dimensions.join('、') || '关联报表没有暴露稳定拆分维度,执行前需要按报表页面设置确认。'}\n- 便签规则:${notes.length ? '看板便签可用于理解业务目的、注意事项和共享边界;精确口径仍以下属报表为准。' : '没有看板便签。'}\n- 使用边界:当前数值、客户名单和趋势结果需要实时执行看板或下属报表;知识库只提供路由、口径和边界。`;
|
|
842
1035
|
}
|
|
843
1036
|
|
|
844
1037
|
function renderReportAgentUsageSummary(report, metadataRefs, calculationContext, sqlSummary) {
|
|
@@ -847,8 +1040,8 @@ function renderReportAgentUsageSummary(report, metadataRefs, calculationContext,
|
|
|
847
1040
|
const purpose = usefulSemanticText(sqlSummary?.business_purpose) || reportPurpose(report);
|
|
848
1041
|
const questions = usefulSemanticList(sqlSummary?.applicable_questions)
|
|
849
1042
|
? array(sqlSummary.applicable_questions).map(renderPlainSemanticItem)
|
|
850
|
-
:
|
|
851
|
-
const metrics = array(report.metric_occurrences).map(occurrenceSentence);
|
|
1043
|
+
: reportApplicableQuestions(report);
|
|
1044
|
+
const metrics = topDomainFacts(array(report.metric_occurrences).map(occurrenceSentence), 12);
|
|
852
1045
|
const parameters = reportParameterSummaryItems(calculationContext);
|
|
853
1046
|
const dimensions = reportDimensionSummaryItems(report, sqlSummary, calculationContext, metadataRefs);
|
|
854
1047
|
const filters = reportFilterSummaryItems(report, calculationContext);
|
|
@@ -856,7 +1049,21 @@ function renderReportAgentUsageSummary(report, metadataRefs, calculationContext,
|
|
|
856
1049
|
const boundaries = usefulSemanticList(sqlSummary?.non_applicable_questions)
|
|
857
1050
|
? array(sqlSummary.non_applicable_questions).map(renderPlainSemanticItem)
|
|
858
1051
|
: ['不能替代实时执行结果;当前知识库只说明报表语义和使用边界。'];
|
|
859
|
-
return `- 用途:${purpose}\n- 适合回答:\n${questions.map((item) => ` - ${item}`).join('\n') || ' -
|
|
1052
|
+
return `- 用途:${purpose}\n- 适合回答:\n${questions.map((item) => ` - ${item}`).join('\n') || ' - 适合在进入报表后核验该资产标题对应的业务问题。'}\n- 主要指标/输出:\n${metrics.map((item) => ` - ${item}`).join('\n') || ' - 资产包没有暴露稳定指标或输出字段,使用时需要回到源报表核验。'}\n- 输入参数:\n${parameters.map((item) => ` - ${item}`).join('\n') || ' - 本报表没有需要 Agent 预先解释的运行参数。'}\n- 常用下钻维度:${dimensions.join('、') || '资产包没有暴露稳定拆分维度;如需分组比较,应先打开报表确认可用维度。'}\n- 关键过滤与限制:\n${[...filters, ...limits].map((item) => ` - ${item}`).join('\n') || ' - 资产包没有暴露固定过滤、排序或行数限制;执行前按报表页面设置确认。'}\n- 使用边界:\n${boundaries.map((item) => ` - ${item}`).join('\n')}`;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
function reportApplicableQuestions(report) {
|
|
1056
|
+
const title = text(report.title || report.resource_key);
|
|
1057
|
+
const metricNames = topDomainFacts(array(report.metric_occurrences).map(occurrenceLabel).filter(Boolean), 4);
|
|
1058
|
+
const dimensions = reportDimensionSummaryItems(report, null, calculationContextForKb(report), metadataRefsForReport(report)).slice(0, 4);
|
|
1059
|
+
const filters = reportFilterSummaryItems(report, object(report.calculation_context)).slice(0, 2);
|
|
1060
|
+
const subject = metricNames.length ? metricNames.join('、') : title;
|
|
1061
|
+
const result = [
|
|
1062
|
+
`查看“${title}”对应的${subject}。`,
|
|
1063
|
+
dimensions.length ? `按${dimensions.join('、')}拆分比较${subject}。` : '',
|
|
1064
|
+
filters.length ? `在${filters.join(';')}条件下解释${subject}。` : '',
|
|
1065
|
+
].filter(Boolean);
|
|
1066
|
+
return [...new Set(result)];
|
|
860
1067
|
}
|
|
861
1068
|
|
|
862
1069
|
function renderReportMetricOccurrencesSection(report) {
|
|
@@ -871,13 +1078,17 @@ function renderSqlReportAgentUsageSummary(report, summary) {
|
|
|
871
1078
|
return '_当前 SQL 报表没有可用的 Agent 语义摘要。该报表只能作为待核验线索,不能直接回答确定口径。_';
|
|
872
1079
|
}
|
|
873
1080
|
const purpose = usefulSemanticText(summary.business_purpose) || reportPurpose(report);
|
|
874
|
-
return
|
|
1081
|
+
return `- 定义状态: ${text(summary.definition_state) || 'unknown'}\n- 用途:${purpose}\n- 统计粒度: ${text(summary.statistical_grain) || 'unknown'}\n- 证据定位: \`${text(summary.evidence_locator) || 'unknown'}\`\n\n### 输入参数\n\n${renderSemanticList(summary.input_parameters, renderSqlInputParameterItem)}\n\n### 输出字段\n\n${renderSemanticList(summary.output_fields, (item) => renderSqlSemanticItem(item, summary))}\n\n### 关键过滤与排除\n\n${renderSemanticList(summary.key_filters, (item) => renderSqlSemanticItem(item, summary))}\n\n### 默认限制与排序\n\n${renderSemanticList(summary.default_limits, (item) => renderSqlSemanticItem(item, summary))}\n\n### 可回答的问题\n\n${renderSemanticList(summary.applicable_questions, (item) => renderSqlSemanticItem(item, summary))}\n\n### 不可安全回答的问题\n\n${renderSemanticList(summary.non_applicable_questions, (item) => renderSqlSemanticItem(item, summary))}`;
|
|
875
1082
|
}
|
|
876
1083
|
|
|
877
1084
|
function renderSqlSemanticItem(value, summary) {
|
|
878
1085
|
return replaceSqlParameterMentions(renderSemanticItem(value), summary);
|
|
879
1086
|
}
|
|
880
1087
|
|
|
1088
|
+
function renderSqlInputParameterItem(value) {
|
|
1089
|
+
return sanitizeVisibleSqlSemanticText(renderSemanticItem(value));
|
|
1090
|
+
}
|
|
1091
|
+
|
|
881
1092
|
function replaceSqlParameterMentions(value, summary) {
|
|
882
1093
|
let result = sanitizeVisibleSqlSemanticText(value);
|
|
883
1094
|
for (const [name, meaning] of sqlParameterMeaningEntries(summary)) {
|
|
@@ -923,6 +1134,11 @@ function genericSqlParameterMeaning(name) {
|
|
|
923
1134
|
return normalized;
|
|
924
1135
|
}
|
|
925
1136
|
|
|
1137
|
+
function isGeneratedSqlParameterName(name) {
|
|
1138
|
+
return /^(?:selector|variable|text|number|partdate)\d*$/i.test(text(name))
|
|
1139
|
+
|| /^date\d+$/i.test(text(name));
|
|
1140
|
+
}
|
|
1141
|
+
|
|
926
1142
|
function escapeRegExp(value) {
|
|
927
1143
|
return text(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
928
1144
|
}
|
|
@@ -944,9 +1160,12 @@ function renderPlainSemanticItem(value) {
|
|
|
944
1160
|
if (item.default_value != null && text(item.default_value)) extras.push(`default=${text(item.default_value)}`);
|
|
945
1161
|
const expressionKind = text(item.expression_kind);
|
|
946
1162
|
if (expressionKind) extras.push(expressionKind);
|
|
947
|
-
if (isInputParameterSemanticItem(item) && meaning && name) {
|
|
1163
|
+
if (isInputParameterSemanticItem(item) && meaning && name && !isGeneratedSqlParameterName(name)) {
|
|
948
1164
|
return [`${meaning}(\`${name}\`)`, extras.join(',')].filter(Boolean).join(':');
|
|
949
1165
|
}
|
|
1166
|
+
if (isInputParameterSemanticItem(item) && meaning) {
|
|
1167
|
+
return [meaning, extras.join(',')].filter(Boolean).join(':');
|
|
1168
|
+
}
|
|
950
1169
|
return [name ? `\`${name}\`` : '', meaning, extras.join(',')].filter(Boolean).join(':') || jsonInline(item);
|
|
951
1170
|
}
|
|
952
1171
|
|
|
@@ -981,7 +1200,7 @@ function reportDimensionSummaryItems(report, summary = null, calculationContext
|
|
|
981
1200
|
...array(object(context.event_view).groups).map(text),
|
|
982
1201
|
...array(refs).map((ref) => namedCodeFact(ref.title || ref.display_name, ref.resource_key)),
|
|
983
1202
|
];
|
|
984
|
-
return topDomainFacts(candidates.filter(
|
|
1203
|
+
return topDomainFacts(candidates.filter(isUsefulDomainDimensionFact), 12);
|
|
985
1204
|
}
|
|
986
1205
|
|
|
987
1206
|
function reportParameterSummaryItems(calculationContext) {
|
|
@@ -1096,6 +1315,8 @@ function sanitizeKeyFilters(values) {
|
|
|
1096
1315
|
|
|
1097
1316
|
function sanitizeVisibleSqlSemanticText(value) {
|
|
1098
1317
|
let normalized = text(value)
|
|
1318
|
+
.replace(/SQL\s*使用\s*select\s+\*\s*[,,]\s*输出字段需以源表\s*([^,。]+?)\s*当前结构为准/gi, '源表全字段输出,字段清单需回源表 $1 当前结构确认')
|
|
1319
|
+
.replace(/\bselect\s+\*/gi, '源表全字段输出')
|
|
1099
1320
|
.replace(/\$\{(?:(?:Text|Selector|PartDate|Number|Date|DateTime|MultiSelector)\s*:)?\s*([A-Za-z_][\w.-]*)\s*\}/g, '$1')
|
|
1100
1321
|
.replace(/SQL\s*输出字段[::]?/gi, '')
|
|
1101
1322
|
.replace(/来源表达式[::]?/g, '')
|
|
@@ -1127,6 +1348,21 @@ function dedupeSemicolonSegments(value) {
|
|
|
1127
1348
|
return result.join(';');
|
|
1128
1349
|
}
|
|
1129
1350
|
|
|
1351
|
+
function stripClausePunctuation(value) {
|
|
1352
|
+
return text(value).replace(/[。;;,,\s]+$/u, '');
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
function joinChineseClauses(value) {
|
|
1356
|
+
const values = array(value).map(stripClausePunctuation).filter(Boolean);
|
|
1357
|
+
return values.join(';') || '无';
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
function renderNumberedSteps(value, indent = '') {
|
|
1361
|
+
const values = array(value).map(stripClausePunctuation).filter(Boolean);
|
|
1362
|
+
if (!values.length) return `${indent}- 无`;
|
|
1363
|
+
return values.map((item, index) => `${indent}${index + 1}. ${item}`).join('\n');
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1130
1366
|
function renderSemanticList(value, renderer) {
|
|
1131
1367
|
const values = array(value);
|
|
1132
1368
|
if (!values.length) return '- 无';
|
|
@@ -1143,9 +1379,12 @@ function renderSemanticItem(value) {
|
|
|
1143
1379
|
.filter(([key]) => !['name', 'field', 'key', 'column', 'title', 'meaning', 'description', 'remark', 'purpose'].includes(key))
|
|
1144
1380
|
.map(([key, itemValue]) => `${key}=${inlineSemanticValue(itemValue)}`)
|
|
1145
1381
|
.join(', ');
|
|
1146
|
-
if (isInputParameterSemanticItem(item) && meaning && name) {
|
|
1382
|
+
if (isInputParameterSemanticItem(item) && meaning && name && !isGeneratedSqlParameterName(name)) {
|
|
1147
1383
|
return [`${meaning}(\`${name}\`)`, details].filter(Boolean).join(':') || jsonInline(item);
|
|
1148
1384
|
}
|
|
1385
|
+
if (isInputParameterSemanticItem(item) && meaning) {
|
|
1386
|
+
return [meaning, details].filter(Boolean).join(':') || jsonInline(item);
|
|
1387
|
+
}
|
|
1149
1388
|
return [name ? `\`${name}\`` : '', meaning, details].filter(Boolean).join(':') || jsonInline(item);
|
|
1150
1389
|
}
|
|
1151
1390
|
|
|
@@ -1817,10 +2056,20 @@ function appendConflict(target, id, message) {
|
|
|
1817
2056
|
}
|
|
1818
2057
|
|
|
1819
2058
|
function semanticConflictSummary(kind, key, values, signatureLabelFn) {
|
|
1820
|
-
const rows = values
|
|
2059
|
+
const rows = [...values]
|
|
2060
|
+
.sort((left, right) => semanticConflictAssetSortKey(left).localeCompare(semanticConflictAssetSortKey(right), 'en'))
|
|
2061
|
+
.map((row) => `${assetDisplayName(row)}(${assetIdentity(row)},${signatureLabelFn(row)})`);
|
|
1821
2062
|
return `语义“${key}”存在 ${values.length} 个${kind}候选,但口径不同:${rows.join(';')}。Agent 不应仅凭名称选择,需要优先使用业务域/召回卡或让用户确认。`;
|
|
1822
2063
|
}
|
|
1823
2064
|
|
|
2065
|
+
function semanticConflictAssetSortKey(row) {
|
|
2066
|
+
return [
|
|
2067
|
+
assetIdentity(row),
|
|
2068
|
+
text(row.resource_type),
|
|
2069
|
+
text(row.evidence_id),
|
|
2070
|
+
].join('\u0000');
|
|
2071
|
+
}
|
|
2072
|
+
|
|
1824
2073
|
function reportSemanticKey(report) {
|
|
1825
2074
|
return normalizeSemanticIntent(text(report.title)) || normalizeSemanticIntent(array(report.metric_occurrences).map(occurrenceLabel).join(' '));
|
|
1826
2075
|
}
|
|
@@ -1929,7 +2178,7 @@ function renderOccurrence(item, index) {
|
|
|
1929
2178
|
|
|
1930
2179
|
- 事件: ${event}
|
|
1931
2180
|
- 复用指标 key: ${text(item.metric_key) ? `\`${text(item.metric_key)}\`` : '无'}
|
|
1932
|
-
- 聚合方式: ${aggregationLabel(item) || '
|
|
2181
|
+
- 聚合方式: ${aggregationLabel(item) || '资产包未暴露聚合方式'}
|
|
1933
2182
|
- 度量字段: ${readableMetricText(item.measure_title || item.measure_key) || '无'}
|
|
1934
2183
|
- 公式表达式: ${expression ? `\`${expression}\`` : '无'}
|
|
1935
2184
|
- 公式依赖: ${formulaSummary || '无'}
|
|
@@ -1945,9 +2194,10 @@ function occurrenceSentence(item) {
|
|
|
1945
2194
|
return `${label}:公式指标${expression ? `,表达式为 \`${expression}\`` : ''}${dependencies.length ? `,依赖${dependencies.join('、')}` : ''}。`;
|
|
1946
2195
|
}
|
|
1947
2196
|
const event = metricEventLabel(item) || '未知事件';
|
|
1948
|
-
const aggregation = aggregationLabel(item)
|
|
2197
|
+
const aggregation = aggregationLabel(item);
|
|
1949
2198
|
const measure = readableMetricText(item.measure_title || item.measure_key);
|
|
1950
|
-
|
|
2199
|
+
const aggregationPart = aggregation ? `按“${aggregation}”计算` : '计算,资产包未暴露聚合方式';
|
|
2200
|
+
return `${label}:基于“${event}”${aggregationPart}${measure ? `,度量字段为“${measure}”` : ''}${text(item.metric_key) ? `,复用指标 key 为 \`${text(item.metric_key)}\`` : ''}。`;
|
|
1951
2201
|
}
|
|
1952
2202
|
|
|
1953
2203
|
function formulaExpression(item) {
|
|
@@ -1972,7 +2222,7 @@ function formulaDependencies(item) {
|
|
|
1972
2222
|
const event = object(object(dependency).event);
|
|
1973
2223
|
const quota = object(object(dependency).quota);
|
|
1974
2224
|
const eventName = text(event.eventDesc || event.eventName) || '未知事件';
|
|
1975
|
-
const aggregation = text(quota.quotaDesc || quota.quotaName) || '
|
|
2225
|
+
const aggregation = text(quota.quotaDesc || quota.quotaName) || '资产包未暴露聚合方式';
|
|
1976
2226
|
const filters = array(object(event.filter).filts)
|
|
1977
2227
|
.map((filter) => text(object(filter).columnDesc || object(filter).quotDesc || object(filter).prop))
|
|
1978
2228
|
.filter(Boolean);
|
|
@@ -2163,9 +2413,13 @@ function readableMetricText(value) {
|
|
|
2163
2413
|
function groupLabel(group) { return text(object(group).columnDesc || object(group).columnName || group); }
|
|
2164
2414
|
|
|
2165
2415
|
function renderSemanticConflictList() {
|
|
2166
|
-
const reportLines = [...reportConflicts.entries()]
|
|
2167
|
-
|
|
2168
|
-
|
|
2416
|
+
const reportLines = [...reportConflicts.entries()]
|
|
2417
|
+
.sort(([left], [right]) => left.localeCompare(right, 'en'))
|
|
2418
|
+
.map(([id, conflicts]) =>
|
|
2419
|
+
`- [${link(reportById.get(id)?.title || id)}](../briefs/reports/${reportFiles.get(id)}):${conflicts.join(';')}`);
|
|
2420
|
+
const metadataLines = [...metadataSemanticConflicts.entries()]
|
|
2421
|
+
.sort(([left], [right]) => left.localeCompare(right, 'en'))
|
|
2422
|
+
.map(([id, conflicts]) => {
|
|
2169
2423
|
const item = metadata.find((row) => text(row.evidence_id) === id);
|
|
2170
2424
|
if (!item) return `- \`${id}\`:${conflicts.join(';')}`;
|
|
2171
2425
|
return `- [${link(metadataDisplayTitle(item))}](../briefs/metadata/${metadataDirectory(item.resource_type)}/${metadataFiles.get(id)}):${conflicts.join(';')}`;
|
|
@@ -2202,7 +2456,7 @@ function renderCoverage() {
|
|
|
2202
2456
|
|
|
2203
2457
|
## 技术附录
|
|
2204
2458
|
|
|
2205
|
-
${appendices.map((row) => `- [${link(row.title)}](../appendices/${appendixFiles.get(text(row.appendix_id))})`).join('\n') || '- 无'}
|
|
2459
|
+
${sort(appendices, 'appendix_id').map((row) => `- [${link(row.title)}](../appendices/${appendixFiles.get(text(row.appendix_id))})`).join('\n') || '- 无'}
|
|
2206
2460
|
|
|
2207
2461
|
## 技术来源容器
|
|
2208
2462
|
|
|
@@ -2210,13 +2464,13 @@ ${containerAssetLinks(technicalContainers)}
|
|
|
2210
2464
|
|
|
2211
2465
|
## 无物理空间看板
|
|
2212
2466
|
|
|
2213
|
-
${assetLinks(unassignedDashboards, dashboardFiles, '../dashboards')}
|
|
2467
|
+
${assetLinks(sort(unassignedDashboards, 'resource_key'), dashboardFiles, '../dashboards')}
|
|
2214
2468
|
|
|
2215
2469
|
## 独立报表
|
|
2216
2470
|
|
|
2217
2471
|
这些报表没有看板承载,保留为可检索资产,但不根据名称强行推断业务域。
|
|
2218
2472
|
|
|
2219
|
-
${assetLinks(standaloneReports, reportFiles, '../reports')}
|
|
2473
|
+
${assetLinks(sort(standaloneReports, 'resource_key'), reportFiles, '../reports')}
|
|
2220
2474
|
|
|
2221
2475
|
## 语义冲突
|
|
2222
2476
|
|
|
@@ -2224,7 +2478,7 @@ ${renderSemanticConflictList()}
|
|
|
2224
2478
|
|
|
2225
2479
|
## 缺少源标题的元数据
|
|
2226
2480
|
|
|
2227
|
-
${metadataMissingTitles.map((item) => `- [\`${link(item.resource_key)}\`](../metadata/${metadataDirectory(item.resource_type)}/${metadataFiles.get(text(item.evidence_id))})`).join('\n') || '- 无'}
|
|
2481
|
+
${sort(metadataMissingTitles, 'evidence_id').map((item) => `- [\`${link(item.resource_key)}\`](../metadata/${metadataDirectory(item.resource_type)}/${metadataFiles.get(text(item.evidence_id))})`).join('\n') || '- 无'}
|
|
2228
2482
|
`;
|
|
2229
2483
|
}
|
|
2230
2484
|
|
|
@@ -2347,7 +2601,7 @@ function assetLinks(values, files, prefix) {
|
|
|
2347
2601
|
}
|
|
2348
2602
|
|
|
2349
2603
|
function containerAssetLinks(values) {
|
|
2350
|
-
return values.map((row) => `- [${link(row.container_title || row.container_key)}](../source-containers/${containerFiles.get(text(row.container_key))})(${text(row.container_kind)})`).join('\n') || '- 无';
|
|
2604
|
+
return sort(values, 'container_key').map((row) => `- [${link(row.container_title || row.container_key)}](../source-containers/${containerFiles.get(text(row.container_key))})(${text(row.container_kind)})`).join('\n') || '- 无';
|
|
2351
2605
|
}
|
|
2352
2606
|
|
|
2353
2607
|
function topNames(values, limit = 5) {
|
|
@@ -2524,6 +2778,9 @@ function metadataUsage() {
|
|
|
2524
2778
|
result.get(id).push({ report_id: text(report.resource_key), report_name: text(report.title) });
|
|
2525
2779
|
}
|
|
2526
2780
|
}
|
|
2781
|
+
for (const [id, values] of result.entries()) {
|
|
2782
|
+
result.set(id, values.sort((left, right) => text(left.report_id).localeCompare(text(right.report_id), 'en')));
|
|
2783
|
+
}
|
|
2527
2784
|
return result;
|
|
2528
2785
|
}
|
|
2529
2786
|
|
|
@@ -2536,6 +2793,9 @@ function metadataMetricUsage() {
|
|
|
2536
2793
|
result.get(id).push({ metric_id: text(metric.resource_key), metric_name: text(metric.title) });
|
|
2537
2794
|
}
|
|
2538
2795
|
}
|
|
2796
|
+
for (const [id, values] of result.entries()) {
|
|
2797
|
+
result.set(id, values.sort((left, right) => text(left.metric_id).localeCompare(text(right.metric_id), 'en')));
|
|
2798
|
+
}
|
|
2539
2799
|
return result;
|
|
2540
2800
|
}
|
|
2541
2801
|
|
|
@@ -2622,7 +2882,7 @@ function parseArgs(values) {
|
|
|
2622
2882
|
const token = values[index];
|
|
2623
2883
|
if (!token.startsWith('--')) fail(`Unexpected argument: ${token}`);
|
|
2624
2884
|
const name = token.slice(2);
|
|
2625
|
-
if (['force', 'allow-truncated', 'allow-all-visible'].includes(name)) result[name] = true;
|
|
2885
|
+
if (['force', 'allow-truncated', 'allow-all-visible', 'allow-semantic-plan-snapshot-drift'].includes(name)) result[name] = true;
|
|
2626
2886
|
else {
|
|
2627
2887
|
const value = values[index + 1];
|
|
2628
2888
|
if (!value || value.startsWith('--')) fail(`Missing value for --${name}.`);
|