dsh-data-cleaning-agent 0.8.18 → 0.8.19

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/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.8.19] - 2026-09-09
8
+
9
+ - 受益人与主营业务收入增加待确认候选,明确首条限制及财务口径差异,不自动替换。
10
+ - 映射依次展示搜索、大类、可见字段列表;组合筛选保留已有映射。
11
+ - 区分去重主体处理数与输入行补全数,结果卡片和工作台提供原生预览入口。
12
+ - 零异常时不展示空异常清单;有待核验记录时保留下载。
13
+ - 245 项测试及 10 组浏览器布局回归通过;实际 DSH 宿主点击链路仍需升级后验收。
14
+
7
15
  ## [0.8.18] - 2026-09-09
8
16
 
9
17
  - 新增受益所有人首条名称及首报告期营业总收入、利润总额、总资产,共 136 个字段;共享契约 0.2.0。
package/README.en.md CHANGED
@@ -8,7 +8,7 @@ Related agents: [数据清洗补全](https://github.com/duhu2000/dsh-data-cleani
8
8
 
9
9
  > A data cleaning & completion agent plugin for DeepSeek Harness: local CSV/XLSX/JSON engine plus optional Qichacha (QCC) MCP enterprise-data enrichment. Initiated and maintained by the Qichacha (QCC) team.
10
10
  >
11
- > Current source version / 当前源码版本: **0.8.18** (stable release)
11
+ > Current source version / 当前源码版本: **0.8.19** (stable release)
12
12
 
13
13
  This release unifies spreadsheet previews, column mapping, and enrichment scope across the prompt wizard and workbench. Mapping statuses use color and text; mapped fields automatically enter the scope, with optional extra fields collapsed. Multiple confirmed output columns may share a non-identity field while preserving non-empty values. It fixes saved drafts resetting the scope to five defaults and detects stale Host versions. Preparing a draft does not query QCC; sending starts execution. Fully restart DSH after upgrading. Existing download artifacts are not rewritten.
14
14
 
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # dsh-data-cleaning-agent
2
2
 
3
- 本版统一向导与工作台的 Host 执行闭环:发送后自动生成新 Excel,原文件不修改,工作台入口可恢复;发布记录见 [发布说明](docs/RELEASE-0.8.18.md)。
3
+ 本版统一向导与工作台的 Host 执行闭环:发送后自动生成新 Excel,原文件不修改,工作台入口可恢复;发布记录见 [发布说明](docs/RELEASE-0.8.19.md)。
4
4
 
5
5
  ## 安装与三分钟上手
6
6
 
7
7
  数据清洗补全智能体:面向 Excel/CSV/JSON 企业名单,提供数据清洗、表格清洗、清洗补全、去重、企业数据补全与字段补全,支持企查查 MCP 和结果导出。
8
8
 
9
9
  ```sh
10
- dsh plugin --profile web add dsh-data-cleaning-agent@0.8.18
10
+ dsh plugin --profile web add dsh-data-cleaning-agent@0.8.19
11
11
  ```
12
12
 
13
13
  请先满足下文的 DSH、连接器及侧边栏依赖要求;安装后完整停止并重启对应 Profile。
@@ -25,7 +25,7 @@ dsh plugin --profile web add dsh-data-cleaning-agent@0.8.18
25
25
 
26
26
  > 在 DeepSeek Harness 中清洗、补全、画像企业名单数据的智能体插件:本地 CSV/XLSX/JSON 引擎 + 可选企查查(Qichacha/QCC)MCP 企业数据补全,由企查查(Qichacha/QCC)团队发起并维护。
27
27
  >
28
- > 当前源码版本 / Current source version: **0.8.18**(正式版本)
28
+ > 当前源码版本 / Current source version: **0.8.19**(正式版本)
29
29
 
30
30
  本版上传表格后展示完整清单及空白数量,用绿色、琥珀色、红色及文字区分已通过、待确认和未匹配映射。已映射字段自动纳入补全范围,额外字段默认折叠;多个原列可经确认使用同一非主体字段,分别补空并保留非空原值。修复 Host 草稿重置为默认五字段的问题,增加前后端版本错配提示。生成说明不查询,发送才执行;升级后需完整重启 DSH,历史下载文件不自动改写。
31
31
 
@@ -0,0 +1,13 @@
1
+ # 0.8.19 发布说明
2
+
3
+ 本版修复字段候选、搜索展示和结果交付体验。
4
+
5
+ - “受益人”推荐首条受益所有人;“主营业务收入”推荐营业总收入并提示口径不同,均需人工确认。
6
+ - 映射选择器按当前映射、搜索、大类、字段清单展示;筛选不修改已选映射。
7
+ - 已处理主体数包含未匹配或失败,不代表已补全;同时展示按输入行统计的补全与待核验数。
8
+ - QCC 工具结果卡片与工作台增加原生文件链接,不只依赖模型生成 Markdown。
9
+ - 空异常清单不展示;实际存在异常时保留。
10
+
11
+ 验证:245 项自动测试、10 组明暗色与响应式浏览器回归通过。未发起付费 QCC 查询,未修改上传源文件。实际 DSH 宿主中的文件点击仍需升级后验收。
12
+
13
+ 升级至 0.8.19 后完整重启 DSH。历史对话文本不会自动重写;历史制品可从工作台获取。
package/lib/client.js CHANGED
@@ -1497,7 +1497,8 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
1497
1497
  };
1498
1498
  // 语义不完全等同:只推荐,绝不冒充精确匹配或发起调用。
1499
1499
  const MAPPING_HINTS = {
1500
- 受益所有人: ['beneficial_owner_first_name'], 受益所有人名称: ['beneficial_owner_first_name'], UBO: ['beneficial_owner_first_name'],
1500
+ 受益人: ['beneficial_owner_first_name'], 受益所有人: ['beneficial_owner_first_name'], 受益所有人名称: ['beneficial_owner_first_name'], UBO: ['beneficial_owner_first_name'],
1501
+ 主营业务收入: ['financial_total_revenue'],
1501
1502
  地址: ['registered_address', 'mailing_address', 'invoice_address'],
1502
1503
  address: ['registered_address', 'mailing_address'],
1503
1504
  企业地址: ['registered_address', 'mailing_address'], 公司地址: ['registered_address', 'mailing_address'],
@@ -1524,6 +1525,8 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
1524
1525
  const hints = Object.entries(MAPPING_HINTS).find(([key]) => normalizeMappingLabel(key) === label)?.[1] || [];
1525
1526
  candidates = hints.flatMap((key) => fields.filter(([id]) => id === key));
1526
1527
  reason = candidates.length ? '含义需确认,点击推荐后采用' : '未识别表头,请手动选择';
1528
+ if (candidates.length && label === normalizeMappingLabel('主营业务收入')) reason = '主营业务收入与营业总收入口径不同;确认接受该口径后采用';
1529
+ if (candidates.length && label === normalizeMappingLabel('受益人')) reason = '受益人含义需确认;仅取首条受益所有人,不代表唯一或最大受益人';
1527
1530
  }
1528
1531
  return { sourceField: String(sourceField), candidates, automatic: exact, reason };
1529
1532
  });
@@ -1567,7 +1570,12 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
1567
1570
  const occupied = (id) => isAnchorField(id) && mappings.some((item) => item.sourceField !== sourceField && item.targetField === id);
1568
1571
  const fields = groups.flatMap(([, , items]) => items);
1569
1572
  const label = fields.find(([id]) => id === value)?.[1] || '不参与匹配 / 补全';
1570
- const matches = (id, name) => normalizeMappingLabel([id, name, ...(MAPPING_ALIASES[id] || [])].join(' ')).includes(normalizeMappingLabel(query));
1573
+ const matches = (id, name) => normalizeMappingLabel([id, name, ...(MAPPING_ALIASES[id] || []), ...Object.entries(MAPPING_HINTS).filter(([, ids]) => ids.includes(id)).map(([hint]) => hint)].join(' ')).includes(normalizeMappingLabel(query));
1574
+ const filteredGroups = groups.filter(([id]) => !category || id === category)
1575
+ .map(([id, title, items]) => [id, title, items.filter(([key, name]) => matches(key, name))])
1576
+ .filter(([, , items]) => items.length);
1577
+ const filteredFields = filteredGroups.flatMap(([, , items]) => items);
1578
+ const hiddenSelection = value && !filteredFields.some(([id]) => id === value);
1571
1579
  return h('div', { className: 'dcAgentMappingRow' },
1572
1580
  h('span', { title: sourceField }, sourceField), h('b', { 'aria-hidden': 'true' }, '→'),
1573
1581
  h('div', { style: { minWidth: 0 } },
@@ -1578,20 +1586,21 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
1578
1586
  }
1579
1587
  } },
1580
1588
  h('summary', { className: 'dcAgentField', 'aria-label': `${sourceField} 当前映射` }, label),
1589
+ h('input', { className: 'dcAgentField', value: query, placeholder: '模糊搜索字段名称 / 英文键 / 别名', 'aria-label': `${sourceField} 搜索映射字段`, onChange: (event) => setQuery(event.target.value) }),
1581
1590
  h('select', { className: 'dcAgentField', value: category, 'aria-label': `${sourceField} 映射大类`, onChange: (event) => setCategory(event.target.value) },
1582
1591
  h('option', { value: '' }, '全部维度'),
1583
1592
  groups.map(([id, title]) => h('option', { key: id, value: id }, title))),
1584
- h('input', { className: 'dcAgentField', value: query, placeholder: '搜索字段名称 / 英文键 / 别名', 'aria-label': `${sourceField} 搜索映射字段`, onChange: (event) => setQuery(event.target.value) }),
1585
- h('select', { className: 'dcAgentField', value, 'aria-label': `${sourceField} 字段映射`, onChange: (event) => {
1593
+ h('select', { className: 'dcAgentField', size: 8, style: { height: 'auto', minHeight: '180px' }, value, 'aria-label': `${sourceField} 字段映射`, onChange: (event) => {
1586
1594
  onChange(sourceField, event.target.value);
1587
1595
  const details = event.currentTarget.closest('details');
1588
1596
  if (details) { details.open = false; details.querySelector('summary')?.focus(); }
1589
1597
  } },
1590
1598
  h('option', { value: '' }, '不参与匹配 / 补全'),
1591
- groups.filter(([id, , items]) => !category || id === category || items.some(([key]) => key === value)).map(([id, title, items]) => h('optgroup', { key: id, label: title }, items.filter(([key, name]) => key === value || ((!category || category === id) && matches(key, name))).map(([key, name]) =>
1599
+ hiddenSelection ? h('option', { value, disabled: true }, `当前选择:${label}(不符合筛选,保持不变)`) : null,
1600
+ filteredGroups.map(([id, title, items]) => h('optgroup', { key: id, label: title }, items.map(([key, name]) =>
1592
1601
  h('option', { key, value: key, disabled: occupied(key) }, `${name}${occupied(key) ? '(已被其他列使用)' : ''}`)))),
1593
1602
  ),
1594
- (query || category) && !groups.filter(([id]) => !category || id === category).flatMap(([, , items]) => items).some(([id, name]) => matches(id, name)) ? h('p', { className: 'dcAgentHint', role: 'status' }, '无匹配字段;当前选择保持不变。') : null,
1603
+ h('p', { className: 'dcAgentHint', role: 'status' }, filteredFields.length ? `匹配 ${filteredFields.length} 个字段;选择后采用。` : '无匹配字段;当前选择保持不变。'),
1595
1604
  ),
1596
1605
  value === 'beneficial_owner_first_name' || value.startsWith('financial_') ? h('p', { className: 'dcAgentHint' }, value === 'beneficial_owner_first_name' ? '仅取返回首条受益所有人,不代表唯一或最大受益人。' : '取返回首个报告期,不跨期补值;报告期保留在结果取值说明中。') : null,
1597
1606
  h('small', { className: 'dcAgentMappingStatus', 'data-status': value ? 'confirmed' : recommendation.candidates.length ? 'review' : 'unmatched',
@@ -3165,6 +3174,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
3165
3174
 
3166
3175
  /** 模型工具 tool.call.toolview 卡片元数据(wire 名 → 展示文案)。 */
3167
3176
  const TOOL_VIEW_META = {
3177
+ data_cleaning_qcc_run: { icon: '🧩', label: '企查查清洗补全结果', hint: '已处理包含未匹配或失败;不等于已补全。' },
3168
3178
  data_clean_rows: { icon: '🧹', label: '数据清洗', hint: '去重 · 剔除非法金额 · 缺失补 0' },
3169
3179
  data_complete_rows: { icon: '🧩', label: '数据补全', hint: '名称 / 金额 / 手机号归一' },
3170
3180
  data_profile: { icon: '🩺', label: '数据体检', hint: '缺失率 · 去重值 · 金额分布' },
@@ -3203,6 +3213,9 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
3203
3213
  ),
3204
3214
  meta.hint ? h('div', { className: 'dcAgentToolCardHint' }, meta.hint) : null,
3205
3215
  summary ? h('div', { className: 'dcAgentToolCardBody' }, summary) : null,
3216
+ toolName === 'data_cleaning_qcc_run' ? h('div', { className: 'dcAgentArtifactList' },
3217
+ [...summary.matchAll(/\[([^\]]+)\]\((\/data-cleaning\/api\/workflow\/tasks\/[a-zA-Z0-9%_-]+\/artifacts\/[a-zA-Z0-9%_-]+(?:\?preview=1)?)\)/g)].map((match, index) =>
3218
+ h('a', { key: index, className: 'dcAgentButton', href: match[2], target: '_blank', rel: 'noopener noreferrer' }, match[1]))) : null,
3206
3219
  );
3207
3220
  }
3208
3221
 
@@ -4343,10 +4356,10 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4343
4356
  h('div', { className: 'dcAgentRow' }, h('button', { type: 'button', className: 'dcAgentButton is-primary', onClick: () => actions.setStep('download') }, '进入下载数据')),
4344
4357
  );
4345
4358
  } else if (step === 'download') {
4346
- const availableArtifacts = cachedTask?.artifacts || [];
4359
+ const availableArtifacts = (cachedTask?.artifacts || []).filter(artifact => artifact.kind !== 'review' || artifact.rowCount > 0);
4347
4360
  const canCreateArtifacts = Boolean(exportRows()?.length) && ['rules_confirmed', 'diagnosed', 'export_ready', 'partial'].includes(cachedTask?.state);
4348
4361
  pane = h('div', { className: 'dcAgentPane' },
4349
- h('p', { className: 'dcAgentHint' }, '结果与异常清单由 Host 生成 CSV/XLSX 四件套并耐久保存。任务或插件重启后,可从任务历史继续下载;无需再次调用企查查。'),
4362
+ h('p', { className: 'dcAgentHint' }, '结果文件由 Host 保存;仅在有待核验记录时展示异常清单。任务或插件重启后,可从任务历史继续下载;无需再次调用企查查。'),
4350
4363
  h('div', { className: 'dcAgentGrid' },
4351
4364
  stat('输入行数', dataset ? dataset.rowCount : workflowTask?.source?.rowCount ?? '—'),
4352
4365
  stat('匹配补全', qccEnrichedCount, qccEnrichedCount > 0 ? 'good' : null),
@@ -4354,6 +4367,11 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4354
4367
  stat('任务状态', WORKFLOW_STATE_LABELS[cachedTask?.state] || cachedTask?.state || '进行中'),
4355
4368
  ),
4356
4369
  availableArtifacts.length ? h('div', { className: 'dcAgentArtifactList' },
4370
+ availableArtifacts.filter(artifact => artifact.format === 'xlsx').map(artifact => h('a', {
4371
+ key: 'preview-' + artifact.id, className: 'dcAgentButton',
4372
+ href: `/data-cleaning/api/workflow/tasks/${encodeURIComponent(cachedTask.id)}/artifacts/${encodeURIComponent(artifact.id)}?preview=1`,
4373
+ target: '_blank', rel: 'noopener noreferrer',
4374
+ }, `预览 / 打开:${artifact.fileName}`)),
4357
4375
  availableArtifacts.map((artifact) => h('button', {
4358
4376
  key: artifact.id,
4359
4377
  type: 'button',
@@ -4366,8 +4384,8 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4366
4384
  h('div', { className: 'dcAgentRow' },
4367
4385
  h('button', { type: 'button', className: 'dcAgentButton is-primary', disabled: busy || !canCreateArtifacts, onClick: () => createAndDownload('complete', 'xlsx') }, '生成并下载结果 XLSX'),
4368
4386
  h('button', { type: 'button', className: 'dcAgentButton', disabled: busy || !canCreateArtifacts, onClick: () => createAndDownload('complete', 'csv') }, '生成并下载结果 CSV'),
4369
- h('button', { type: 'button', className: 'dcAgentButton', disabled: busy || !canCreateArtifacts, onClick: () => createAndDownload('review', 'xlsx') }, '生成并下载异常清单 XLSX'),
4370
- h('button', { type: 'button', className: 'dcAgentButton', disabled: busy || !canCreateArtifacts, onClick: () => createAndDownload('review', 'csv') }, '生成并下载异常清单 CSV'),
4387
+ qccReviewCount > 0 ? h('button', { type: 'button', className: 'dcAgentButton', disabled: busy || !canCreateArtifacts, onClick: () => createAndDownload('review', 'xlsx') }, '生成并下载异常清单 XLSX') : null,
4388
+ qccReviewCount > 0 ? h('button', { type: 'button', className: 'dcAgentButton', disabled: busy || !canCreateArtifacts, onClick: () => createAndDownload('review', 'csv') }, '生成并下载异常清单 CSV') : null,
4371
4389
  ),
4372
4390
  !canCreateArtifacts ? h('p', { className: 'dcAgentHint' }, '请先完成规则确认与清洗补全;历史任务若尚未生成制品,需要重新上传源文件。') : null,
4373
4391
  ),
@@ -4517,7 +4535,8 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4517
4535
  h('b', null, WORKFLOW_STATE_LABELS[cachedTask.state] || cachedTask.state),
4518
4536
  h('p', { className: 'dcAgentHint' }, `任务:${cachedTask.id}`),
4519
4537
  h('p', null, `${cachedTask.source?.type === 'image' ? '图片识别' : cachedTask.source?.type === 'text' ? '粘贴名单' : '上传表格'} · ${cachedTask.source?.fileName || ''} · ${cachedTask.source?.rowCount || 0} 条 · ${cachedTask.fieldSelection?.length || 0} 个补全字段`),
4520
- commandProgress?.taskId === cachedTask.id && Number.isFinite(commandProgress.totalUnique) ? h('p', null, `已处理主体 ${commandProgress.completedUnique}/${commandProgress.totalUnique}(去重后,含未匹配或失败)`) : null,
4538
+ commandProgress?.taskId === cachedTask.id && Number.isFinite(commandProgress.totalUnique) ? h('p', null, `已处理主体 ${commandProgress.completedUnique}/${commandProgress.totalUnique}(去重后,含未匹配或失败,不代表补全成功)`) : null,
4539
+ h('p', null, `已补全 ${qccEnrichedCount} 条 · 待核验 ${qccReviewCount} 条(按输入行统计)`),
4521
4540
  ) : null,
4522
4541
  error ? h('div', { className: 'dcAgentError', role: 'alert' }, error) : null,
4523
4542
  step !== 'history' ? h('details', { className: 'dcAgentSection' },
@@ -4612,7 +4631,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4612
4631
 
4613
4632
  // 模型工具的 tool.call.toolview 富化卡片(keyed by wire name,替代裸 JSON 摘要)。
4614
4633
  // 说明:分三条独立 inject(而非 generator)——测试 shim 对 inject 回调仅执行一次并 push 其返回值。
4615
- const toolviewKeys = ['data_clean_rows', 'data_complete_rows', 'data_profile', 'data_cleaning_extract_image_companies'];
4634
+ const toolviewKeys = ['data_clean_rows', 'data_complete_rows', 'data_profile', 'data_cleaning_extract_image_companies', 'data_cleaning_qcc_run'];
4616
4635
  for (const key of toolviewKeys) {
4617
4636
  ctx.slots.inject('tool.call.toolview', () => ctx.slots.register({
4618
4637
  name: 'tool.call.toolview',
@@ -265,7 +265,7 @@ export class QccCommandStore {
265
265
  state: run.state,
266
266
  summary: run.summary,
267
267
  ...(record.delivery ? { deliveryState: record.delivery.state, artifactCount: record.delivery.artifacts.length,
268
- artifacts: record.delivery.artifacts.filter(a => a.format === 'xlsx').map(a => ({ fileName: a.fileName, url: `/data-cleaning/api/workflow/tasks/${encodeURIComponent(record.taskId)}/artifacts/${encodeURIComponent(a.id)}` })) } : {}),
268
+ artifacts: record.delivery.artifacts.filter(a => a.format === 'xlsx' && (a.kind !== 'review' || a.rowCount > 0)).map(a => ({ fileName: a.fileName, url: `/data-cleaning/api/workflow/tasks/${encodeURIComponent(record.taskId)}/artifacts/${encodeURIComponent(a.id)}` })) } : {}),
269
269
  });
270
270
  }
271
271
  }
@@ -313,7 +313,7 @@ export function registerQccCommandTool(tools, commands) {
313
313
  },
314
314
  render: (_args, value) => [{
315
315
  type: 'text',
316
- text: `数据清洗补全:${value.summary?.enriched ?? 0}/${value.summary?.totalRows ?? 0} 条已补全。${value.artifactCount ? 'Host 已生成新的结果 XLSX,请返回工作台「结果下载」。源文件未修改,无需再次确认或提供路径。' : value.deliveryState === 'review_required' ? '存在多候选,请返回工作台确认主体。' : '请返回工作台查看任务状态。'}\n${(value.artifacts || []).map(a => `${String(a.fileName).replace(/[^a-zA-Z0-9\u4e00-\u9fff._ -]/g, '_')}:[预览 / 打开](${a.url}?preview=1) · [下载 Excel](${a.url})`).join('\n')}`,
316
+ text: `处理结束:已处理 ${value.summary?.uniqueCompanies ?? 0} 个去重主体(含未匹配或失败);按输入行统计:${value.summary?.enriched ?? 0}/${value.summary?.totalRows ?? 0} 条已补全。未匹配 ${value.summary?.unresolved ?? 0} 条、失败 ${value.summary?.failed ?? 0} 条、多候选 ${value.summary?.ambiguous ?? 0} 条、字段待核验 ${value.summary?.fieldReview ?? 0} 条。不得仅凭补全为 0 推断授权异常;请依据实际错误记录。${value.artifactCount ? 'Host 已生成新的结果 XLSX,请返回工作台「结果下载」。源文件未修改,无需再次确认或提供路径。' : value.deliveryState === 'review_required' ? '存在多候选,请返回工作台确认主体。' : '请返回工作台查看任务状态。'}\n${(value.artifacts || []).map(a => `${String(a.fileName).replace(/[^a-zA-Z0-9\u4e00-\u9fff._ -]/g, '_')}:[预览 / 打开](${a.url}?preview=1) · [下载 Excel](${a.url})`).join('\n')}`,
317
317
  }],
318
318
  },
319
319
  async execute(args, exec) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-data-cleaning-agent",
3
- "version": "0.8.18",
3
+ "version": "0.8.19",
4
4
  "description": "Data cleaning and data enrichment for CSV/XLSX/JSON enterprise lists in DeepSeek Harness, including spreadsheet cleaning, deduplication, profiling, optional Qichacha MCP and exports.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -40,7 +40,7 @@
40
40
  "docs/RELEASE-0.8.1.md",
41
41
  "docs/RELEASE-0.8.16.md",
42
42
  "docs/RELEASE-0.8.17.md",
43
- "docs/RELEASE-0.8.18.md",
43
+ "docs/RELEASE-0.8.19.md",
44
44
  "docs/TEMPLATE-MAPPING-ACCEPTANCE.md",
45
45
  "docs/UI-WORKFLOW-V2.md",
46
46
  "docs/UI-WORKFLOW-V2-MIGRATION.md",
@@ -1,15 +0,0 @@
1
- # 0.8.18
2
-
3
- 新增共享首条快照契约(qcc-field-contracts 0.2.0),目录共 136 个字段。
4
-
5
- - 受益所有人仅取工具返回首条名称,不代表唯一或最大受益人;不以经营管理人员替代。
6
- - 财务三项取同一个首返回报告期的主要财务指标,缺项留空,不跨期拼接;保留 0、原始精度、报告期与披露等级。
7
- - 映射大类与关键词联合筛选,当前选择不因过滤丢失。十一类按工商、联系方式、实控人、受益所有人、简介、财务、税务、上市、进出口、自身风险、关联风险排序。
8
- - 执行中的任务每秒读取 Host 命令状态与任务元数据。显示来源方式、文件名、输入条数、补全字段数、去重后已处理主体数;已处理不等于成功补全。
9
- - 对话工具结果包含实际任务的 XLSX 链接:浏览器安全预览前 50 行、下载完整新文件。原上传文件不修改。
10
-
11
- ## 验证
12
-
13
- 使用合成返回测试首条规则、缺失和精度;验证原列补空、多列映射及 Host 跨重挂载下载。浏览器回归覆盖明暗主题及五种视口。无真实企查查收费查询。
14
-
15
- 升级后完整重启 DSH 并重新生成任务说明;旧凭证不改写。