@thinkingai/ae-cli 6.1.27 → 6.1.28
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 +29 -3
- package/README.zh.md +29 -3
- package/dist/{auth-WA7YGGRT.js → auth-NKD5Z5BQ.js} +150 -38
- package/dist/{automation-VAAQBM7Y.js → automation-K32V2NKP.js} +94 -38
- package/dist/{capability-GAAYJ3IQ.js → capability-4CGSL7PK.js} +9 -8
- package/dist/{chunk-CT7QDJS6.js → chunk-2IYIYSUO.js} +2 -2
- package/dist/{chunk-3YVEAZUN.js → chunk-2UWS5CUP.js} +32 -21
- package/dist/{chunk-6VNIR4AP.js → chunk-ELCR235M.js} +26 -19
- package/dist/{chunk-RPBOAQQQ.js → chunk-GI5BMEZO.js} +1 -1
- package/dist/{chunk-7KU2WNQE.js → chunk-GTPWDLTE.js} +7 -6
- package/dist/chunk-JJJIP2XQ.js +105 -0
- package/dist/{chunk-5XJYLEVC.js → chunk-KHS64JZQ.js} +4 -4
- package/dist/{chunk-ZL7SGNIA.js → chunk-LMCYSVVA.js} +11 -13
- package/dist/{chunk-OP44TT4H.js → chunk-P6VFCH3P.js} +4 -2
- package/dist/{chunk-GHXZK54S.js → chunk-P7KL7IOH.js} +41 -13
- package/dist/{chunk-AP7YP2NX.js → chunk-QSAR3GHY.js} +2 -2
- package/dist/{chunk-VZZNLV3I.js → chunk-QW3R6O7L.js} +14 -6
- package/dist/{chunk-S6M42KND.js → chunk-T44M3PLZ.js} +1 -1
- package/dist/{chunk-AQJPNWZF.js → chunk-UF244C5C.js} +3 -3
- package/dist/{chunk-MWIA43UJ.js → chunk-UJ7UPRXK.js} +3 -3
- package/dist/{chunk-Q5US7JC5.js → chunk-UUD5RB36.js} +3 -3
- package/dist/chunk-X7DRLE62.js +233 -0
- package/dist/{chunk-WNGFSIOB.js → chunk-ZW4VMY5H.js} +103 -6
- package/dist/{community-report-client-PEERQCX2.js → community-report-client-S2K3A3Q6.js} +1 -1
- package/dist/{config-JOD5DOPE.js → config-ASSAAIOI.js} +6 -5
- package/dist/{context-NGVFPCBK.js → context-6RWLVOM5.js} +4 -4
- package/dist/{data-integration-BCLQFTGU.js → data-integration-EXSUPUDZ.js} +6 -6
- package/dist/evaluation-5YT4QLCL.js +3714 -0
- package/dist/index.js +96 -52
- package/dist/{local-data-upload-client-TWMHFLUA.js → local-data-upload-client-7HCPGIS3.js} +1 -1
- package/dist/{memory-CQKH2JAV.js → memory-VCYLVPMI.js} +6 -6
- package/dist/{metadata-NR3PHR23.js → metadata-YGI5M6OF.js} +8 -8
- package/dist/{model-VX5M2CJ6.js → model-DPJHSD73.js} +4 -4
- package/dist/{personal-semantic-preference-2RAI36P3.js → personal-semantic-preference-76TBKAPY.js} +6 -6
- package/dist/{project-semantic-3BUGP3ZM.js → project-semantic-XOEBO2Q5.js} +6 -6
- package/dist/{sync-RZIAV37C.js → sync-7PP6KQ75.js} +7 -7
- package/dist/{te-agent-AORRE2FM.js → te-agent-PJVAPKBD.js} +753 -94
- package/dist/{te-analysis-GP7DSQ7Q.js → te-analysis-OX62G5VD.js} +411 -79
- package/dist/{te-community-42M7ICDO.js → te-community-QN3WMPNT.js} +6 -4
- package/dist/{te-dataops-BNKNZ4F2.js → te-dataops-UKD2XN3E.js} +8 -6
- package/dist/{te-engage-2CO6LRCX.js → te-engage-X3DIXPRA.js} +6 -6
- package/dist/{te-experiment-652CLXMU.js → te-experiment-MEIIK3DP.js} +6 -6
- package/dist/{te-kb-ULATOTQ3.js → te-kb-73EWDFDF.js} +7 -7
- package/dist/{te-system-UGHVKBVV.js → te-system-IE7NCKC3.js} +6 -6
- package/dist/{te-team-YA6SNOJ3.js → te-team-MGQ5CNRW.js} +63 -41
- package/dist/{things-DTCOQIQB.js → things-4JIBCA55.js} +7 -7
- package/dist/{update-ESNYKUVR.js → update-AX66IFMJ.js} +4 -4
- package/dist/{workspace-JEOHKFPX.js → workspace-Q5NMEKEN.js} +6 -6
- package/package.json +13 -8
- package/skills/ae-agent/SKILL.md +22 -3
- package/skills/ae-agent/references/command_index.md +8 -0
- package/skills/ae-agent/references/resource-package.md +53 -0
- package/skills/ae-analysis/SKILL.md +12 -3
- package/skills/ae-analysis/references/adhoc_export.md +1 -1
- package/skills/ae-analysis/references/agent_review_preflight.md +4 -0
- package/skills/ae-analysis/references/agent_review_submit_to_page.md +4 -0
- package/skills/ae-analysis/references/ai_models/event.md +58 -2
- package/skills/ae-analysis/references/ai_models/rank_list.md +1 -0
- package/skills/ae-analysis/references/ai_models/retention.md +2 -0
- package/skills/ae-analysis/references/ai_models/revenue.md +2 -0
- package/skills/ae-analysis/references/analysis_data_export.md +11 -1
- package/skills/ae-analysis/references/asset_batch_info_export.md +2 -2
- package/skills/ae-analysis/references/asset_batch_sql_export.md +2 -2
- package/skills/ae-analysis/references/asset_export.md +1 -1
- package/skills/ae-analysis/references/bi_panel_page_data_export.md +1 -1
- package/skills/ae-analysis/references/check_export.md +1 -1
- package/skills/ae-analysis/references/command_index.md +34 -25
- package/skills/ae-analysis/references/dashboard_report_data_export.md +2 -0
- package/skills/ae-analysis/references/dashboard_report_get.md +6 -2
- package/skills/ae-analysis/references/dashboard_report_update.md +24 -5
- package/skills/ae-analysis/references/feedback_submit.md +1 -1
- package/skills/ae-analysis/references/governance_recommendation_export.md +10 -2
- package/skills/ae-analysis/references/live_data_export.md +1 -1
- package/skills/ae-analysis/references/metric_create.md +29 -0
- package/skills/ae-analysis/references/metric_get.md +2 -0
- package/skills/ae-analysis/references/metric_update.md +2 -0
- package/skills/ae-analysis/references/operation_record_export.md +1 -1
- package/skills/ae-analysis/references/plan_change_log_export.md +1 -1
- package/skills/ae-analysis/references/plan_export.md +1 -1
- package/skills/ae-analysis/references/project_info_get.md +4 -0
- package/skills/ae-analysis/references/project_member_group_add_members.md +35 -0
- package/skills/ae-analysis/references/project_member_group_create.md +25 -0
- package/skills/ae-analysis/references/project_member_group_delete.md +34 -0
- package/skills/ae-analysis/references/project_member_group_list.md +29 -0
- package/skills/ae-analysis/references/project_member_group_members.md +28 -0
- package/skills/ae-analysis/references/project_member_group_remove_members.md +35 -0
- package/skills/ae-analysis/references/project_member_group_rename.md +26 -0
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +6 -1
- package/skills/ae-analysis/references/report_data_export.md +1 -1
- package/skills/ae-analysis/references/scenario_append.md +25 -0
- package/skills/ae-analysis/references/scenario_collect.md +35 -0
- package/skills/ae-analysis/references/scenario_evaluation.md +30 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +73 -4
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md +5 -1
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/execution-contract.mjs +173 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +109 -64
- package/skills/ae-automation/SKILL.md +2 -2
- package/skills/ae-automation/references/cli.md +18 -1
- package/skills/ae-capability/SKILL.md +7 -3
- package/skills/ae-evaluation/SKILL.md +83 -0
- package/skills/ae-evaluation/references/access-and-members.md +55 -0
- package/skills/ae-evaluation/references/connections.md +78 -0
- package/skills/ae-evaluation/references/datasets.md +57 -0
- package/skills/ae-evaluation/references/evaluators.md +81 -0
- package/skills/ae-evaluation/references/files.md +33 -0
- package/skills/ae-evaluation/references/integrations.md +39 -0
- package/skills/ae-evaluation/references/runs.md +160 -0
- package/skills/ae-evaluation/references/schedules.md +31 -0
- package/skills/ae-kb/SKILL.md +1 -2
- package/skills/ae-metadata/SKILL.md +2 -1
- package/skills/ae-metadata/references/metadata_data_table_download.md +7 -1
- package/skills/ae-metadata/references/metadata_data_table_get.md +2 -0
- package/skills/ae-system/SKILL.md +1 -1
- package/skills/ae-team/SKILL.md +2 -2
- package/skills/ae-team/references/run-start.md +1 -0
- package/skills/ae-team/references/run-watch.md +7 -5
- package/skills/ae-things/SKILL.md +53 -51
- package/skills/ae-things/references/cli.md +56 -54
- package/skills/ae-things-progress/SKILL.md +20 -20
- package/skills/ae-things-review/SKILL.md +19 -19
- package/skills/ae-workspace/SKILL.md +1 -1
- package/dist/chunk-CI24BDR2.js +0 -43
package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import fs from 'node:fs';
|
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { precompiledSource, normalizeSourceForHash } from './precompiled-source.mjs';
|
|
10
|
+
import { reportContract } from './execution-contract.mjs';
|
|
10
11
|
|
|
11
12
|
const require = createRequire(import.meta.url);
|
|
12
13
|
const archiverModule = require('archiver');
|
|
@@ -259,6 +260,7 @@ try {
|
|
|
259
260
|
personal_semantic_integrations: planModel.personalSemanticIntegrations.length,
|
|
260
261
|
blocked_assets: blockedCount, unknown_sql_reports: unknownSqlCount },
|
|
261
262
|
quality_warnings: [...asArray(corpus.warnings),
|
|
263
|
+
...planModel.cards.filter(card => !card.routing).map(card => `Recall card ${card.card_id} has legacy routing; precise intent branches require semantic review.`),
|
|
262
264
|
...(sourceProjectRefs.filter((row) => Number(row.source_project_id) !== semanticProjectId).length
|
|
263
265
|
? [`${sourceProjectRefs.filter((row) => Number(row.source_project_id) !== semanticProjectId).length} packaged asset reference(s) mention another project: ${sourceProjectRefs.filter((row) => Number(row.source_project_id) !== semanticProjectId).slice(0, 5).map((row) => `${row.resource_type}:${row.resource_key}->${row.source_project_id}`).join(', ')}`] : []),
|
|
264
266
|
...(unknownSqlCount ? [`${unknownSqlCount} SQL reports have unknown semantics and are blocked.`] : []),
|
|
@@ -350,6 +352,22 @@ function validateSemanticPlan() {
|
|
|
350
352
|
fail(`Recall card ${cardId} routing branch references an asset outside preferred/fallback refs.`);
|
|
351
353
|
}
|
|
352
354
|
}
|
|
355
|
+
const combination = asObject(branch.combination);
|
|
356
|
+
if (branch.combination != null) {
|
|
357
|
+
if (!['compatible', 'incompatible', 'unknown'].includes(clean(combination.compatibility))) fail(`Recall card ${cardId} has invalid combination compatibility.`);
|
|
358
|
+
if (!clean(combination.reason)) fail(`Recall card ${cardId} combination requires an evidence-based reason.`);
|
|
359
|
+
if (combination.compatibility === 'compatible'
|
|
360
|
+
&& (!asArray(combination.join_keys).length || !clean(combination.time_alignment))) {
|
|
361
|
+
fail(`Recall card ${cardId} compatible combination requires join_keys and time_alignment.`);
|
|
362
|
+
}
|
|
363
|
+
for (const ref of asArray(branch.asset_refs).filter(ref => ref.resource_type === 'report')) {
|
|
364
|
+
const summary = asArray(semanticPlan.sql_report_semantics).find(row => clean(row.report_id) === clean(ref.resource_key));
|
|
365
|
+
if (summary && combination.compatibility === 'compatible'
|
|
366
|
+
&& asArray(combination.join_keys).some(key => !asArray(summary.output_fields).some(field => clean(field.name) === clean(key)))) {
|
|
367
|
+
fail(`Recall card ${cardId} join key is not an output field of report ${ref.resource_key}.`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
353
371
|
}
|
|
354
372
|
}
|
|
355
373
|
for (const ref of asArray(card.excluded_asset_refs)) {
|
|
@@ -691,6 +709,7 @@ function writeMergedAsset(wikiRoot, directory, asset, authority, extra = '') {
|
|
|
691
709
|
const id = clean(asset.resource_key);
|
|
692
710
|
const source = readText(path.join(buildIr, directory, fileName(directory.slice(0, -1), id)))
|
|
693
711
|
.replaceAll('../appendices/', '../technical-appendices/')
|
|
712
|
+
.replace(/^- 定义状态:\s*(valid|unknown|conflict)\s*$/m, `- 定义状态: ${authority.definition_state}`)
|
|
694
713
|
.replace(/- 源详情: `([^`]+)`/g, '- 资产包源定位(精确证据已内嵌): `$1`');
|
|
695
714
|
const brief = readText(path.join(buildIr, 'briefs', directory, fileName(directory.slice(0, -1), id)));
|
|
696
715
|
const type = directory === 'dashboards' ? 'project-dashboard' : directory === 'reports' ? 'project-report' : 'project-reusable-metric';
|
|
@@ -755,8 +774,11 @@ ${asArray(values).map((ref) => {
|
|
|
755
774
|
const routing = asObject(card.routing);
|
|
756
775
|
const branches = asArray(routing.branches).map((branch) => {
|
|
757
776
|
const item = asObject(branch);
|
|
758
|
-
const targets = asArray(item.asset_refs).map(recallAssetLabel).join('、') || '回到业务域核对资产';
|
|
759
|
-
|
|
777
|
+
const targets = asArray(item.asset_refs).map(ref => `[${escapeLink(recallAssetLabel(ref))}](${assetPath(clean(ref.resource_type), clean(ref.resource_key))})`).join('、') || '回到业务域核对资产';
|
|
778
|
+
const combination = asObject(item.combination);
|
|
779
|
+
const combinationNote = asArray(item.asset_refs).filter(ref => ref.resource_type !== 'dashboard').length > 1
|
|
780
|
+
? ` Combination: ${clean(combination.compatibility) || 'unknown'}; ${clean(combination.reason) || 'Verify common population, stable identity, grain and time before combining.'}${asArray(combination.join_keys).length ? ` Keys: ${asArray(combination.join_keys).join(', ')}.` : ''}${clean(combination.time_alignment) ? ` Time: ${clean(combination.time_alignment)}.` : ''}${asArray(combination.missing_coverage).length ? ` Gaps: ${asArray(combination.missing_coverage).join('; ')}.` : ''}` : '';
|
|
781
|
+
return `- 当${clean(item.when)}:使用 ${targets}。${clean(item.reason)}${combinationNote}`;
|
|
760
782
|
});
|
|
761
783
|
return `---
|
|
762
784
|
type: project-semantic-recall-card
|
|
@@ -801,6 +823,8 @@ ${refs(card.fallback_asset_refs, '备选资产')}
|
|
|
801
823
|
|
|
802
824
|
${refs(card.excluded_asset_refs, '排除资产')}
|
|
803
825
|
|
|
826
|
+
${renderRecallEvidence(card)}
|
|
827
|
+
|
|
804
828
|
## 实时执行边界
|
|
805
829
|
|
|
806
830
|
- 是否需要执行实时数据:${Boolean(card.requires_live_execution)}
|
|
@@ -816,11 +840,48 @@ function recallAssetLabel(ref) {
|
|
|
816
840
|
: type === 'report' ? reportById.get(key)
|
|
817
841
|
: type === 'metric' ? metricById.get(key)
|
|
818
842
|
: null;
|
|
819
|
-
const title = assetReadableTitle({ ...asObject(row), title: ref.display_name || ref.title
|
|
843
|
+
const title = assetReadableTitle({ ...asObject(row), title: row?.title || ref.display_name || ref.title, resource_key: key }, type);
|
|
820
844
|
const identity = `${type}:${key}`;
|
|
821
845
|
return title && title !== key ? `${title}(${identity})` : identity;
|
|
822
846
|
}
|
|
823
847
|
|
|
848
|
+
function renderRecallEvidence(card) {
|
|
849
|
+
const refs = [...asArray(card.preferred_asset_refs), ...asArray(card.fallback_asset_refs),
|
|
850
|
+
...asArray(asObject(card.routing).branches).flatMap(branch => asArray(branch.asset_refs))];
|
|
851
|
+
const seen = new Set();
|
|
852
|
+
const lines = [];
|
|
853
|
+
for (const ref of refs) {
|
|
854
|
+
const identity = `${ref.resource_type}:${ref.resource_key}`;
|
|
855
|
+
if (seen.has(identity) || !['report', 'metric'].includes(ref.resource_type)) continue;
|
|
856
|
+
seen.add(identity);
|
|
857
|
+
const report = ref.resource_type === 'report' ? reportById.get(clean(ref.resource_key)) : null;
|
|
858
|
+
const summary = report ? planModel.sqlByReportId.get(clean(ref.resource_key)) : null;
|
|
859
|
+
const facts = report ? reportContract(report) : null;
|
|
860
|
+
const parameters = summary ? asArray(summary.input_parameters).map(item => `${clean(item.name)}: ${clean(item.meaning)}`) : [];
|
|
861
|
+
const measures = summary ? [] : asArray(report?.metric_occurrences).map(item =>
|
|
862
|
+
[clean(item.display_name || item.event_title || item.event_name), clean(item.aggregation_name || item.aggregation_code)].filter(Boolean).join(': '));
|
|
863
|
+
const savedScope = !summary && facts && Object.keys(facts.time).length ? ` Saved time scope: ${JSON.stringify(facts.time)}.` : '';
|
|
864
|
+
const reportSource = summary ? readText(path.join(buildIr, 'reports', fileName('report', clean(ref.resource_key)))) : '';
|
|
865
|
+
const outputs = summary ? asArray(summary.output_fields).map(item => {
|
|
866
|
+
const name = clean(item.name);
|
|
867
|
+
const unverified = reportSource.split('\n').some(line => line.startsWith(`- \`${name}\``) && line.includes('output identity unverified'));
|
|
868
|
+
if (unverified && asArray(asObject(card.routing).branches).some(branch =>
|
|
869
|
+
branch.combination?.compatibility === 'compatible'
|
|
870
|
+
&& asArray(branch.combination.join_keys).includes(name)
|
|
871
|
+
&& asArray(branch.asset_refs).some(asset => asset.resource_type === 'report' && clean(asset.resource_key) === clean(ref.resource_key)))) {
|
|
872
|
+
fail(`Recall card ${card.card_id} join key has unverified output identity in report ${ref.resource_key}: ${name}.`);
|
|
873
|
+
}
|
|
874
|
+
return `${name}${unverified ? ' (identity unknown)' : ''}`;
|
|
875
|
+
}) : [];
|
|
876
|
+
const reminders = summary ? [
|
|
877
|
+
...asArray(summary.calculation_rules).slice(0, 1).map(item => clean(item.meaning)),
|
|
878
|
+
...['time_semantics', 'coverage_gaps'].flatMap(key => asArray(summary[key]).map(item => clean(item.meaning))),
|
|
879
|
+
] : [];
|
|
880
|
+
lines.push(`- [${escapeLink(recallAssetLabel(ref))}](${assetPath(ref.resource_type, clean(ref.resource_key))}): ${clean(summary?.business_purpose) || clean(ref.reason)} Grain: ${clean(summary?.statistical_grain) || (facts ? JSON.stringify(facts.groups) : 'verify the asset definition')}.${parameters.length ? ` Parameters: ${parameters.join('; ')}.` : ''}${outputs.length ? ` Outputs: ${outputs.join(', ')}.` : ''}${measures.length ? ` Measures (verify result column identities): ${measures.join('; ')}.` : ''}${savedScope}${reminders.length ? ` Reminders: ${reminders.join('; ')}.` : ''}`);
|
|
881
|
+
}
|
|
882
|
+
return lines.length ? `## Minimum asset evidence\n\n${lines.join('\n')}\n\nVerify only dashboard notes, inherited filters or timezone settings that affect the chosen route. Asset visibility does not establish runtime data permissions.` : '';
|
|
883
|
+
}
|
|
884
|
+
|
|
824
885
|
function renderRecallCardIndex(cards) {
|
|
825
886
|
return `# 场景召回卡\n\n先按问法、对象、粒度和参数选择匹配的卡;卡内按条件分支找到最小证据并在满足停止条件后停止。无匹配卡时,回到[业务领域](../domains/index.md),按对象、粒度、过滤和时间筛选域内资产;仍无可用资产时说明具体缺口。\n\n${cards.map((card) => `- [${escapeLink(card.intent || card.card_id)}](${fileName('recall-card', card.card_id)})(${clean(card.domain_title)})`).join('\n')}\n`;
|
|
826
887
|
}
|
|
@@ -1481,7 +1542,15 @@ function semanticPlanFragmentRefsForSource(identity, rel) {
|
|
|
1481
1542
|
if (rel === 'wiki/project-overview.md') refs.add('project:model');
|
|
1482
1543
|
if (sourceKind === 'domain' && assetKey) refs.add(`domain:${assetKey}`);
|
|
1483
1544
|
if (sourceKind === 'appendix' && assetKey) refs.add(`appendix:${assetKey}`);
|
|
1484
|
-
if (sourceKind === 'recall-card' && assetKey)
|
|
1545
|
+
if (sourceKind === 'recall-card' && assetKey) {
|
|
1546
|
+
refs.add(`recall-card:${assetKey}`);
|
|
1547
|
+
const card = planModel.cards.find(card => clean(card.card_id) === assetKey);
|
|
1548
|
+
for (const ref of [...asArray(card?.preferred_asset_refs), ...asArray(card?.fallback_asset_refs)]) {
|
|
1549
|
+
if (ref.resource_type === 'report' && planModel.sqlByReportId.has(clean(ref.resource_key))) {
|
|
1550
|
+
refs.add(`report:${clean(ref.resource_key)}:sql_semantics`);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1485
1554
|
if (sourceKind === 'personal-semantic' && assetKey) {
|
|
1486
1555
|
refs.add(`personal-semantic-integration:${assetKey}`);
|
|
1487
1556
|
}
|
package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 项目语义知识库编译准则
|
|
2
2
|
|
|
3
|
-
预置版本:1.
|
|
3
|
+
预置版本:1.2。导航分类版本:2.1。
|
|
4
4
|
|
|
5
5
|
## 总体要求
|
|
6
6
|
|
|
@@ -27,6 +27,10 @@
|
|
|
27
27
|
|
|
28
28
|
不得将安全状态当作过时占位信息而忽略。保留认证状态、定义有效性、冲突、运行时策略和召回限制。已认证的资产仍可能存在定义未知的情况。仅作为依赖的资产可以解释定义、依赖关系和冲突,但不能独立证明业务状态或当前结果。遵守平台访问权限;权限不足时,不得改用其他项目或扩大范围来替代。
|
|
29
29
|
|
|
30
|
+
源文件中的 `Execution contract`、计算证据及组合适用性是需要保留的口径事实。完整保留条件树的 AND/OR 与层级、公式各操作数的过滤和时间窗、去重实体、单位与取整、数组展开、模型窗口、人群条件、聚合参数和保存设置。参数身份、输出列名、显示名和解释分别保留,不互相替换。保存默认值与本次执行覆盖值不能混为一谈;行为日期不证明维表或用户表的历史状态。
|
|
31
|
+
|
|
32
|
+
召回卡内已存在的精确资产路线、参数角色、组合键和覆盖缺口应直接保留,不退回宽泛目录。组合为 `unknown` 或 `incompatible` 时,不改写为可以直接关联。缺行、零值、空数组和未知分母保持区别;补证仅针对尚未确认的候选范围,不假定用户有底层 SQL 权限。计算证据与源定义不一致时记录冲突,不临场补写公式、修正源 SQL 或套用固定日期与阈值。
|
|
33
|
+
|
|
30
34
|
## 权威性与补充知识
|
|
31
35
|
|
|
32
36
|
- 资产定义、治理事实和实时结果保留各自的权威性。决策或纠正仅在明确的目标、内容、日期、状态和适用范围内覆盖其他材料;时间较新本身不足以构成覆盖依据。
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// Structural facts only. Business meanings and asset routes remain Agent-authored.
|
|
2
|
+
const obj = value => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
3
|
+
const list = value => Array.isArray(value) ? value : [];
|
|
4
|
+
const valueOf = value => {
|
|
5
|
+
if (typeof value !== 'string') return value;
|
|
6
|
+
try { return JSON.parse(value); } catch { return value; }
|
|
7
|
+
};
|
|
8
|
+
const present = value => value !== undefined && value !== null && value !== '';
|
|
9
|
+
const pick = (source, keys) => Object.fromEntries(keys.filter(key => present(source[key])).map(key => [key, source[key]]));
|
|
10
|
+
const displayKeys = new Set(['display_name', 'eventNameDisplay', 'eventDesc', 'analysisDesc', 'quotaDesc', 'columnDesc', 'eventUuid', 'uuid']);
|
|
11
|
+
|
|
12
|
+
export function semanticValue(value) {
|
|
13
|
+
if (Array.isArray(value)) return value.map(semanticValue);
|
|
14
|
+
if (!value || typeof value !== 'object') return value;
|
|
15
|
+
return Object.fromEntries(Object.keys(value).filter(key => !displayKeys.has(key)).sort()
|
|
16
|
+
.map(key => [key, semanticValue(value[key])]));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function semanticTime(value) {
|
|
20
|
+
const time = { ...obj(value) };
|
|
21
|
+
if (present(time.recentDay ?? time.recent_day)) {
|
|
22
|
+
for (const key of ['startTime', 'endTime', 'start_time', 'end_time']) delete time[key];
|
|
23
|
+
}
|
|
24
|
+
return time;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function logicalRelation(value) {
|
|
28
|
+
const relation = String(value ?? '').toLowerCase();
|
|
29
|
+
return ({ '1': 'AND', '0': 'OR', and: 'AND', or: 'OR' })[relation] || `UNKNOWN(${relation || 'unspecified'})`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function conditionTree(value, relation) {
|
|
33
|
+
if (Array.isArray(value)) return { relation: logicalRelation(relation), items: value.map(item => conditionTree(item)) };
|
|
34
|
+
const source = obj(value);
|
|
35
|
+
const nested = source.filts ?? source.items ?? source.filters;
|
|
36
|
+
if (nested != null) {
|
|
37
|
+
if (!Array.isArray(nested)) return { unknown: true, raw: source };
|
|
38
|
+
return { relation: logicalRelation(source.relation ?? source.junctionKind ?? relation), items: nested.map(item => conditionTree(item)) };
|
|
39
|
+
}
|
|
40
|
+
if (!Object.keys(source).length) return { unknown: true };
|
|
41
|
+
return { predicate: source };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function renderConditionTree(value, leaf) {
|
|
45
|
+
if (value.predicate) return leaf(value.predicate);
|
|
46
|
+
if (value.unknown) return 'Unknown predicate; verify the source definition';
|
|
47
|
+
if (!value.items.length) return 'No conditions in this scope';
|
|
48
|
+
if (value.items.length === 1) return renderConditionTree(value.items[0], leaf);
|
|
49
|
+
return `(${value.items.map(item => renderConditionTree(item, leaf)).join(` ${value.relation} `)})`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function metricContract(item) {
|
|
53
|
+
const formula = obj(item.formula_definition ?? item.formula);
|
|
54
|
+
return {
|
|
55
|
+
...pick(item, ['event_name', 'aggregation_code', 'measure_key', 'formula_expression', 'entity_grain', 'aggregation_parameters', 'time_scope']),
|
|
56
|
+
filters: item.filters == null ? null : conditionTree(item.filters, item.relation),
|
|
57
|
+
operand_filters: list(item.custom_filters).map(filter => ({ index: filter.index, tree: conditionTree(filter, filter.relation) })),
|
|
58
|
+
operands: list(formula.formulationDeps).map((dependency, index) => ({ index,
|
|
59
|
+
...pick(obj(dependency), ['event', 'quota', 'property', 'date', 'timeRange', 'time_scope', 'quotaTimeRange']),
|
|
60
|
+
})),
|
|
61
|
+
operand_time_ranges: item.quota_time_ranges ?? item.quotaTimeRanges ?? null,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const modelConfigKeys = [
|
|
66
|
+
'windowsGapValue', 'windowsGapUnit', 'percentConfig', 'userCrowds', 'retentionType',
|
|
67
|
+
'rtnRateOrNum', 'statType', 'retentionCollectSet', 'relationProps', 'relationPropSplit',
|
|
68
|
+
'unitNum', 'eventModel', 'taIdMeasureVo',
|
|
69
|
+
];
|
|
70
|
+
const timeKeys = ['recentDay', 'startTime', 'endTime', 'startToNow', 'startToYesterday',
|
|
71
|
+
'timeParticleSize', 'firstDayOfWeek', 'zoneOffset', 'timezone', 'completeIncompletePeriod', 'hideIncompleteData'];
|
|
72
|
+
const interpretedViewKeys = new Set([...timeKeys, ...modelConfigKeys, 'filts', 'groupBy', 'group_by',
|
|
73
|
+
'relation', 'sqlViewParams', 'graphShape', 'projectId', 'displayQuotas', 'displayGroups']);
|
|
74
|
+
|
|
75
|
+
export function reportContract(report, context = report.calculation_context || {}) {
|
|
76
|
+
const view = obj(valueOf(context.event_view));
|
|
77
|
+
const savedParameters = context.saved_parameters ?? view.sqlViewParams ?? null;
|
|
78
|
+
const parameters = list(context.sql_params ?? context.parameters).map(parameter => ({ ...parameter,
|
|
79
|
+
name: parameter.name ?? parameter.paramName,
|
|
80
|
+
}));
|
|
81
|
+
return {
|
|
82
|
+
model: report.report_model,
|
|
83
|
+
groups: context.group_by ?? view.groupBy ?? view.group_by ?? [],
|
|
84
|
+
time: semanticTime({ ...pick(view, timeKeys), ...obj(context.time_scope) }),
|
|
85
|
+
filters: conditionTree(context.filters ?? view.filts ?? [], context.relation ?? view.relation),
|
|
86
|
+
metrics: list(report.metric_occurrences).map(metricContract),
|
|
87
|
+
model_config: { ...pick(view, modelConfigKeys), ...obj(context.model_config) },
|
|
88
|
+
unparsed_model_config: Object.fromEntries(Object.entries(view).filter(([key]) => !interpretedViewKeys.has(key))),
|
|
89
|
+
model_events: list(valueOf(context.source_events)).map(event => pick(obj(event), ['eventName', 'type', 'filts', 'relation', 'analysis', 'analysisParams', 'quota', 'quotaEntities'])),
|
|
90
|
+
parameters,
|
|
91
|
+
saved_parameters: Array.isArray(savedParameters) ? savedParameters.map(parameter => Object.keys(obj(parameter)).length ? semanticTime(parameter) : parameter) : savedParameters,
|
|
92
|
+
sql_projections: report.definition_kind === 'SQL' ? list(obj(context.sql_semantic_facts).final_select?.fields) : [],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function reportSignature(report, context = report.calculation_context || {}, includeSavedSettings = true) {
|
|
97
|
+
const contract = reportContract(report, context);
|
|
98
|
+
contract.time = semanticTime(contract.time);
|
|
99
|
+
if (!includeSavedSettings) contract.unparsed_model_config = {};
|
|
100
|
+
if (report.definition_kind === 'SQL') {
|
|
101
|
+
const definitions = contract.parameters.map(parameter => pick(parameter, ['name', 'paramType', 'type', 'options', 'selectorItems', 'required', 'useTimezone', 'use_timezone']));
|
|
102
|
+
return JSON.stringify(semanticValue({ sql: String(context.sql || '').replace(/\r\n?/g, '\n').trim(),
|
|
103
|
+
parameters: definitions, ...(includeSavedSettings ? { saved_parameters: contract.saved_parameters, time: contract.time } : {}) }));
|
|
104
|
+
}
|
|
105
|
+
return JSON.stringify(semanticValue(contract));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function enrichMetricEvidence(metrics, context) {
|
|
109
|
+
const source = list(valueOf(context.source_events));
|
|
110
|
+
return metrics.map((metric, index) => {
|
|
111
|
+
const raw = obj(source[index]);
|
|
112
|
+
if (source.length !== metrics.length || raw.eventName !== metric.event_name || String(raw.analysis ?? '') !== String(metric.aggregation_code ?? '')) return metric;
|
|
113
|
+
return { ...metric,
|
|
114
|
+
...(raw.analysisParams != null ? { aggregation_parameters: raw.analysisParams } : {}),
|
|
115
|
+
...(raw.quotaEntities != null ? { entity_grain: raw.quotaEntities } : {}),
|
|
116
|
+
...(raw.quotaTimeRanges != null ? { quota_time_ranges: raw.quotaTimeRanges } : {}),
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const inline = value => `\`${JSON.stringify(value).replaceAll('`', '\\`').replaceAll('\n', ' ')}\``;
|
|
122
|
+
|
|
123
|
+
export function renderExecutionContract(contract) {
|
|
124
|
+
const rows = [
|
|
125
|
+
'- These are saved definition settings. Execution overrides and inherited dashboard settings require live verification.',
|
|
126
|
+
'- Saved result grouping is listed below. SQL output grain and inherited settings require the asset explanation; referenced metadata is not a saved group.',
|
|
127
|
+
...contract.groups.map((group, index) => `- Group ${index + 1}: ${inline(group)}`),
|
|
128
|
+
`- Saved population filter structure: ${inline(contract.filters)}`,
|
|
129
|
+
`- Saved time settings: ${Object.keys(contract.time).length ? inline(contract.time) : 'unknown; verify the current definition'}`,
|
|
130
|
+
'- State timing: a historical behavior window does not establish historical values for user or dimension tables. Source refresh times and historical reconstruction require source evidence.',
|
|
131
|
+
'- Empty/missing rows, null, empty arrays, false and zero are distinct. Do not fill missing rows with zero without coverage evidence.',
|
|
132
|
+
];
|
|
133
|
+
if (contract.groups.some(group => /array/i.test(JSON.stringify(group)))) rows.push('- Array grouping can expand an entity into several rows. Distinct counts, ratios and percentiles are not additive across those rows.');
|
|
134
|
+
if (Object.keys(contract.model_config).length) rows.push(`- Model-specific settings: ${inline(contract.model_config)}`);
|
|
135
|
+
if (Object.keys(contract.unparsed_model_config).length) rows.push(`- Uninterpreted saved configuration; semantic support is unknown: ${inline(contract.unparsed_model_config)}`);
|
|
136
|
+
if ((contract.model_config.windowsGapValue != null || list(contract.model_config.userCrowds).length) && contract.model_events.length) rows.push(`- Model event roles and measures: ${inline(contract.model_events)}`);
|
|
137
|
+
if (contract.parameters.length) rows.push(`- Parameter definitions: ${inline(contract.parameters)}`);
|
|
138
|
+
if (contract.saved_parameters != null) rows.push(`- Saved parameter choices (separate from definitions and call-time overrides): ${inline(contract.saved_parameters)}`);
|
|
139
|
+
if (contract.sql_projections.length) {
|
|
140
|
+
const projections = contract.sql_projections.filter(field => !/\$\{/.test(field.expression || ''));
|
|
141
|
+
rows.push(`- SQL outer projection evidence: ${inline(projections)}`);
|
|
142
|
+
rows.push('- SQL lineage completeness: unknown for nested scopes, CTEs, wildcard fields and dynamic expressions. Output names alone do not prove source meanings; verify unresolved columns.');
|
|
143
|
+
}
|
|
144
|
+
for (const [index, metric] of contract.metrics.entries()) {
|
|
145
|
+
if (metric.operands.length || metric.operand_filters.length || metric.aggregation_parameters != null || metric.entity_grain != null) {
|
|
146
|
+
rows.push(`- Measure ${index + 1} calculation scopes: ${inline(metric)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return `\n\n## Execution contract\n\n${rows.join('\n')}\n`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function validateSqlExplanations(summary, sql) {
|
|
153
|
+
const normalize = value => String(value).replace(/\s+/g, ' ').trim();
|
|
154
|
+
for (const key of ['calculation_rules', 'time_semantics', 'coverage_gaps']) {
|
|
155
|
+
if (summary[key] == null) continue;
|
|
156
|
+
if (!Array.isArray(summary[key])) throw new Error(`${key} must be an array.`);
|
|
157
|
+
for (const item of summary[key]) {
|
|
158
|
+
if (!item?.meaning || !item?.evidence || !normalize(sql).includes(normalize(item.evidence))) {
|
|
159
|
+
throw new Error(`${key} requires a meaning and exact SQL evidence from the current definition.`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
for (const field of list(summary.output_fields)) {
|
|
164
|
+
if (field.evidence != null && !normalize(sql).includes(normalize(field.evidence))) {
|
|
165
|
+
throw new Error('Output field lineage evidence must occur in the current SQL.');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function renderSqlExplanations(summary) {
|
|
171
|
+
return ['calculation_rules', 'time_semantics', 'coverage_gaps'].flatMap(key => list(summary?.[key])
|
|
172
|
+
.map(item => `- ${key}: ${item.meaning} (evidence: ${inline(item.evidence)})`)).join('\n');
|
|
173
|
+
}
|