gongwen-skill 2.13.0 → 2.14.0

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/AGENTS.md CHANGED
@@ -118,5 +118,3 @@ gongwen-skill/
118
118
  ## 6. 许可
119
119
 
120
120
  MIT License,详见 [LICENSE](./LICENSE)。
121
- *(内容由AI生成,仅供参考)*
122
- *(内容由AI生成,仅供参考)*
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@
4
4
  Licensed under the MIT License. See the LICENSE file for details.
5
5
  -->
6
6
 
7
+ ## v2.14.0 (2026-09-26)
8
+
9
+ ### Added
10
+ - **解析读取可见性(V2.14)**:文本框内容(`w:txbxContent`,公文红头/发文字号常承载于此)与修订追踪摘要(`w:ins`/`w:del`)正式纳入 DocumentModel(`textboxes` / `revisions` 字段),`parse --json` 结构化输出——此前两者在解析层静默丢失(文本框仅挂非 Pydantic 属性、修订因 python-docx 高层 API 不读 `w:ins` 包裹 run 而整体丢失)
11
+ - **文本框内容检查规则 CHK-TBX001**:检测到文本框但内容为空时提示(红头/发文字号可能缺失);无文本框的文档不触发,避免误报
12
+ - **check/optimize 读取可见性提示**:文档含修订(含作者与增删数)或存在空文本框时,非 JSON 路径显式打印提示,不再静默忽略;`optimize --json` 新增 `textboxes` / `revisions` 字段供 Agent 感知解析降级
13
+ - **未知公文类型显式警告**:check/optimize 对 `-t` 拼错类型不再静默回退 common 规则,打印警告并提示 list-types(发布前全功能测试发现)
14
+ - **新增测试**:`tests/test_read_visibility.py`(文本框入模型、修订摘要、JSON 序列化、普通文档默认值、提示输出、CHK-TBX001、reviewers_count 回归等 7 用例,本地)
15
+
16
+ ### Fixed
17
+ - **npm peer 依赖解析失败(P1,GitHub issue #1)**:`@deepseek-ai/dsh-tools` peer 下限由 `>=0.1.0` 修正为 `>=0.1.5-rc.3`。根因:该包在 npm 上仅发布 rc/alpha 预发布版本(latest tag = `0.0.1-rc.1`),而 npm semver 的预发布 tuple 规则使 `>=0.1.0`(无预发布比较器)无法匹配任何版本,导致 pnpm 安装报 `ERR_PNPM_NO_MATCHING_VERSION`;现对齐官方宿主配套版本(`@deepseek-ai/dsh-base ^0.1.5-rc.3` 传递提供的 dsh-tools)
18
+ - **optimize-content tracked 模式 NameError(P1,发布前全功能测试发现)**:`_run_tracked_mode` 打印「审稿角色」时引用从未赋值的 `reviewers_count`(O10 重构遗留),文档已生成但崩溃 rc=1;现从 `args.reviewers` 取值(full 默认 6 / quick 3),rc 恢复 0
19
+ - **SKILL.md 标题与对外展示名统一**:H1 由「公文文档格式化 Skill(GB/T 9704)」改为「公文全流程处理专家(GB/T 9704)」,三副本(根 / `.dsh/skills/gongwen-skill/SKILL.md` / `.dsh/skills/gongwen-skill.md`)已同步
20
+ - **AGENTS.md 尾部重复行清理**:删除重复的「内容由AI生成,仅供参考」一行
21
+
22
+ ### Changed
23
+ - **README 下载量徽章动态化**:`Downloads-0` 硬编码徽章改为 PyPI 动态下载量徽章(`img.shields.io/pypi/dm/gongwen-skill`)
24
+
7
25
  ## v2.13.0 (2026-09-11)
8
26
 
9
27
  ### Added
package/README.md CHANGED
@@ -18,7 +18,7 @@ Licensed under the MIT License. See the LICENSE file for details.
18
18
  ![Python](https://img.shields.io/badge/Python-3.10%2B-blue.svg)
19
19
  ![GB/T 9704](https://img.shields.io/badge/standard-GB%2FT%209704-red.svg)
20
20
  ![DSH](https://img.shields.io/badge/DSH-Compatible-brightgreen)
21
- ![Downloads](https://img.shields.io/badge/Downloads-0-blue)
21
+ ![Downloads](https://img.shields.io/pypi/dm/gongwen-skill)
22
22
 
23
23
  本 Skill 源自开源桌面项目 [AI 公文智能优化助手](https://github.com/linhut/document-ai-assistant),将其核心格式引擎抽取、剥离桌面端/数据库依赖后独立发行,支持公文的**模板建立、解析、规则检查、自动修复、内容优化、Markdown 转公文**全流程能力。同时原生集成 **DeepSeek Harness (DSH)** 技能系统,支持 DSH Agent 自动发现与加载。
24
24
 
@@ -30,7 +30,7 @@ Licensed under the MIT License. See the LICENSE file for details.
30
30
  |------|------|------|
31
31
  | 📋 列类型 | `list-types` | 列出 25 种支持的公文类型(新增主持词 host_speech;含新闻稿/讲话稿) |
32
32
  | 🏗️ 模板生成 | `template` | 按类型生成 GB/T 9704 标准空白模板 |
33
- | 🔍 解析 | `parse` | `.docx` → 结构化 DocumentModel |
33
+ | 🔍 解析 | `parse` | `.docx` → 结构化 DocumentModel(含文本框/修订摘要) |
34
34
  | ✅ 格式检查 | `check` | 按国标检查,分级 P0/P1/P2(只读) |
35
35
  | 🔧 格式修复 | `optimize` | 自动修复字体/字号/行距/页边距,输出合规文档;`--verify` 单命令闭环自动复查、P0 存在时退出码非 0;`--json` 结构化输出 |
36
36
  | ✍️ **内容优化** | **`optimize-content`** | 内容润色:默认 **Word 原生修订+批注**(审阅面板逐条接受/拒绝),可选行内差异对比版;`--precheck` 预检 changes 与原文一致性、`--preset quick/full/review` 参数收敛 |
package/SKILL.md CHANGED
@@ -19,7 +19,7 @@ metadata:
19
19
  Licensed under the MIT License. See the LICENSE file for details.
20
20
  -->
21
21
 
22
- # 公文文档格式化 Skill(GB/T 9704)
22
+ # 公文全流程处理专家(GB/T 9704)
23
23
 
24
24
  ---
25
25
 
@@ -900,7 +900,7 @@ python -m gongwen fix-common 文件.docx -o 成品.docx
900
900
 
901
901
  | 命令 | 用途 | 最小用法 |
902
902
  |------|------|---------|
903
- | `parse` | .docx → 结构化 DocumentModel JSON | `python -m gongwen parse 公文.docx` |
903
+ | `parse` | .docx → 结构化 DocumentModel JSON(含文本框/修订摘要) | `python -m gongwen parse 公文.docx` |
904
904
  | `check` | 按国标检查格式(只读,分级 P0/P1/P2) | `python -m gongwen check 公文.docx -t notice` |
905
905
  | `audit` | 审计文档:检查删除线/加粗/AI 声明等痕迹 | `python -m gongwen audit 公文.docx` |
906
906
 
package/dsh/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // 公文全流程处理专家 - DSH plugin bridge (gongwen-skill, v2.13.0+)
1
+ // 公文全流程处理专家 - DSH plugin bridge (gongwen-skill, v2.14.0+)
2
2
  // (c) 2026 Jose AI (https://www.linhut.cn)
3
3
  // https://github.com/linhut/gongwen-skill
4
4
  // Licensed under the MIT License. See the LICENSE file for details.
@@ -122,6 +122,32 @@ class HeaderFooter(BaseModel):
122
122
  has_page_number: bool = False # 是否包含页码域
123
123
 
124
124
 
125
+ # ---------------------------------------------------------------------------
126
+ # Read-visibility structures(V2.14:读取可见性)
127
+ # 公文红头/发文字号常承载于文本框(<w:txbxContent>),修订(<w:ins>/<w:del>)
128
+ # 是流转中的草稿核心信息——两者此前在解析层静默丢失,现正式纳入模型。
129
+ # ---------------------------------------------------------------------------
130
+
131
+ class TextBox(BaseModel):
132
+ """文本框内容(红头、发文字号等常承载于文本框)。"""
133
+ index: int = 0
134
+ text: str = ""
135
+ paragraphs: list[str] = Field(default_factory=list)
136
+
137
+
138
+ class RevisionInfo(BaseModel):
139
+ """文档修订追踪摘要(w:ins 新增 / w:del 删除)。"""
140
+ insert_count: int = 0
141
+ delete_count: int = 0
142
+ authors: list[str] = Field(default_factory=list)
143
+ inserted_snippets: list[str] = Field(default_factory=list) # 新增内容片段(前 5 条)
144
+ deleted_snippets: list[str] = Field(default_factory=list) # 删除内容片段(前 5 条)
145
+
146
+ @property
147
+ def has_revisions(self) -> bool:
148
+ return self.insert_count > 0 or self.delete_count > 0
149
+
150
+
125
151
  # ---------------------------------------------------------------------------
126
152
  # Page setup
127
153
  # ---------------------------------------------------------------------------
@@ -170,6 +196,10 @@ class DocumentModel(BaseModel):
170
196
  headers: list[HeaderFooter] = Field(default_factory=list)
171
197
  footers: list[HeaderFooter] = Field(default_factory=list)
172
198
 
199
+ # V2.14:读取可见性——文本框内容与修订摘要(此前静默丢失)
200
+ textboxes: list[TextBox] = Field(default_factory=list)
201
+ revisions: RevisionInfo = Field(default_factory=RevisionInfo)
202
+
173
203
  # Source file info
174
204
  filename: Optional[str] = Field(default=None, exclude=True)
175
205
  source_path: Optional[str] = Field(default=None, exclude=True)
@@ -156,3 +156,42 @@ class OOXMLParser:
156
156
  def para_text_from_element(p_elem) -> str:
157
157
  """从 <w:p> 节点提取文本(NS4 修复:用 iter 遍历后代,与文本框解析一致)。"""
158
158
  return ''.join(t.text or '' for t in p_elem.iter(f'{{{W}}}t'))
159
+
160
+ def parse_revisions(self, docx_path: str | Path) -> Dict[str, Any]:
161
+ """
162
+ 解析文档修订追踪(<w:ins> 新增 / <w:del> 删除)摘要。
163
+
164
+ V2.14:python-docx 高层 API 不读 w:ins 包裹的 run,导致修订内容在
165
+ 解析层静默丢失——此处用 OOXML 树直接统计,让流转中的草稿修订可见。
166
+
167
+ Returns:
168
+ dict: {insert_count, delete_count, authors[], inserted_snippets[], deleted_snippets[]}
169
+ """
170
+ root = self._load_document_xml(docx_path)
171
+ authors: set[str] = set()
172
+ inserted: list[str] = []
173
+ deleted: list[str] = []
174
+
175
+ for ins in root.iter(f'{{{W}}}ins'):
176
+ a = ins.get(f'{{{W}}}author')
177
+ if a:
178
+ authors.add(a)
179
+ txt = ''.join(t.text or '' for t in ins.iter(f'{{{W}}}t'))
180
+ if txt.strip():
181
+ inserted.append(txt.strip())
182
+
183
+ for dl in root.iter(f'{{{W}}}del'):
184
+ a = dl.get(f'{{{W}}}author')
185
+ if a:
186
+ authors.add(a)
187
+ txt = ''.join(t.text or '' for t in dl.iter(f'{{{W}}}delText'))
188
+ if txt.strip():
189
+ deleted.append(txt.strip())
190
+
191
+ return {
192
+ 'insert_count': len(inserted),
193
+ 'delete_count': len(deleted),
194
+ 'authors': sorted(authors),
195
+ 'inserted_snippets': inserted[:5],
196
+ 'deleted_snippets': deleted[:5],
197
+ }
@@ -582,17 +582,37 @@ def parse_docx(file_path: Path | str) -> DocumentModel:
582
582
  logger.info(f"Parsed: {len(paragraphs)} paragraphs, {len(tables)} tables, "
583
583
  f"{len(headers)} headers, {len(footers)} footers")
584
584
 
585
- # I7: 文本框(红头区域)内容暴露给管线——挂载为模型非 Pydantic 属性
585
+ # I7/V2.14: 文本框(红头区域)内容正式入模型——此前仅挂非 Pydantic 属性,
586
+ # JSON 输出与 check/optimize 均不可见(静默丢失);现纳入 DocumentModel.textboxes
587
+ from engine.core.document.models import TextBox
586
588
  try:
587
589
  textboxes = ooxml.parse_textboxes(str(file_path))
590
+ model.textboxes = [
591
+ TextBox(index=tb.index, text=tb.text, paragraphs=tb.paragraphs)
592
+ for tb in textboxes
593
+ ]
594
+ # 向后兼容 alias:仍挂到非标准属性(防外部模块引用)
595
+ object.__setattr__(model, '_textboxes', [tb.text for tb in textboxes])
596
+ object.__setattr__(model, '_textbox_paragraphs', [tb.paragraphs for tb in textboxes])
588
597
  if textboxes:
589
- object.__setattr__(model, '_textboxes', [tb.text for tb in textboxes])
590
- object.__setattr__(model, '_textbox_paragraphs', [tb.paragraphs for tb in textboxes])
591
598
  logger.info(f"Textboxes extracted: {len(textboxes)} (红头/文本框区域)")
592
- else:
593
- object.__setattr__(model, '_textboxes', [])
594
599
  except Exception as e:
595
600
  logger.debug(f"Textbox extraction skipped: {e}")
601
+ object.__setattr__(model, '_textboxes', [])
602
+
603
+ # V2.14: 修订追踪摘要(w:ins/w:del)——此前 python-docx 层静默丢弃
604
+ try:
605
+ rev = ooxml.parse_revisions(str(file_path))
606
+ model.revisions = type(model.revisions)(
607
+ insert_count=rev['insert_count'], delete_count=rev['delete_count'],
608
+ authors=rev['authors'],
609
+ inserted_snippets=rev['inserted_snippets'],
610
+ deleted_snippets=rev['deleted_snippets'],
611
+ )
612
+ if model.revisions.has_revisions:
613
+ logger.info(f"Revisions detected: {rev['insert_count']} ins / {rev['delete_count']} del")
614
+ except Exception as e:
615
+ logger.debug(f"Revision parse skipped: {e}")
596
616
 
597
617
  # I7: 段落索引映射挂载(供批注锚定等下游使用)
598
618
  object.__setattr__(model, '_para_index_map', para_index_map)
@@ -861,7 +861,20 @@ def _check_header_field(model, rule_id: str, severity: str, name: str,
861
861
  field_name = field_path.split(".", 1)[1] if "." in field_path else ""
862
862
 
863
863
  try:
864
- if field_name == "doc_number":
864
+ if field_name == "textbox":
865
+ # V2.14:文本框内容可见性(CHK-TBX001)——红头/发文字号常承载于文本框;
866
+ # 文本框存在但为空 → 提示缺失;无文本框 → 不报(避免误报)
867
+ tb_list = getattr(model, 'textboxes', None) or []
868
+ empty = [tb for tb in tb_list if not (tb.text or '').strip()]
869
+ if tb_list and empty:
870
+ issues.append(CheckIssue(
871
+ rule_id=rule_id, check_type="content", severity=severity,
872
+ name=name, location=f"textbox:{empty[0].index}",
873
+ original_text="",
874
+ suggested_fix=expected,
875
+ reason=message or f"检测到 {len(empty)} 个空文本框(红头/发文字号可能缺失)",
876
+ ))
877
+ elif field_name == "doc_number":
865
878
  # 令号模式:〔2026〕1号 / 第1号 / (2026)1号 / 2026年1号 等
866
879
  all_text = ''.join((getattr(p, 'text', '') or '') for p in model.paragraphs)
867
880
  has_doc_number = re.search(
@@ -7,7 +7,7 @@
7
7
  #
8
8
  # 公文全流程处理专家 - gongwen-skill Python package
9
9
 
10
- __version__ = "2.13.0"
10
+ __version__ = "2.14.0"
11
11
 
12
12
  # 对外展示名(单一事实来源):面向人与模型的运行时展示文案统一引用此常量,
13
13
  # 须与 SKILL.md frontmatter description 首句、.claude-plugin/plugin.json displayName、
@@ -16,7 +16,7 @@ from gongwen.cli.helpers import (
16
16
  parse_config_overrides as _parse_config_overrides,
17
17
  load_rules_with_overrides as _load_rules_with_overrides,
18
18
  )
19
- __version__ = "2.13.0"
19
+ __version__ = "2.14.0"
20
20
  # 版本号应与 gongwen/__init__.py 保持一致,每次发版同步更新
21
21
  """
22
22
  中文公文全流程处理专家 —— 基于 GB/T 9704《党政机关公文格式》国家标准。
@@ -137,7 +137,12 @@ def cmd_parse(args):
137
137
  # --json:强制完整 JSON 到 stdout(即使指定了 -o),Agent 可统一解析
138
138
  print(text)
139
139
  elif args.output:
140
- print(f"已解析: {args.output} ({len(model.paragraphs)} 段落, {len(model.tables)} 表格)")
140
+ parts = [f"{len(model.paragraphs)} 段落", f"{len(model.tables)} 表格"]
141
+ if model.textboxes:
142
+ parts.append(f"{len(model.textboxes)} 文本框")
143
+ if model.revisions.has_revisions:
144
+ parts.append(f"修订 {model.revisions.insert_count}+/{model.revisions.delete_count}-")
145
+ print(f"已解析: {args.output} ({', '.join(parts)})")
141
146
  else:
142
147
  print(text)
143
148
 
@@ -157,6 +162,9 @@ def cmd_check(args):
157
162
  if args.severity:
158
163
  issues = [i for i in issues if i.severity == args.severity]
159
164
 
165
+ # V2.14:未知公文类型显式警告(拼错类型不再静默回退 common)
166
+ _warn_unknown_doc_type(args.doc_type)
167
+
160
168
  if args.json:
161
169
  results = [{
162
170
  "severity": i.severity, "rule_id": i.rule_id, "name": i.name,
@@ -173,6 +181,38 @@ def cmd_check(args):
173
181
  for i in issues:
174
182
  print(f" [{i.severity}] {i.rule_id}: {i.name} @ {i.location}")
175
183
  print(f" 实际: {i.original_text} → 期望: {i.suggested_fix}")
184
+ # V2.14:读取可见性提示——文本框/修订不静默忽略
185
+ _print_read_visibility_hints(model)
186
+
187
+
188
+ def _print_read_visibility_hints(model):
189
+ """V2.14:解析层读取可见性提示。
190
+
191
+ 文本框(红头/发文字号)与修订(w:ins/w:del)是公文流转的高频信息载体,
192
+ 此前在解析层静默丢失;现在解析可见,这里向用户显式告知降级/注意事项。
193
+ """
194
+ if model.textboxes:
195
+ empty = [tb for tb in model.textboxes if not (tb.text or '').strip()]
196
+ if empty:
197
+ print(f" [提示] 检测到 {len(empty)} 个空文本框(红头/发文字号可能缺失)")
198
+ if model.revisions.has_revisions:
199
+ authors = '、'.join(model.revisions.authors) or '未知'
200
+ print(f" [提示] 文档含修订 {model.revisions.insert_count} 处新增 / "
201
+ f"{model.revisions.delete_count} 处删除(作者: {authors});"
202
+ f"检查基于当前可见内容,建议先接受/拒绝修订后再处理")
203
+
204
+
205
+ def _warn_unknown_doc_type(doc_type):
206
+ """V2.14:未知公文类型显式警告(此前静默回退 common 规则,拼错类型难发现)。"""
207
+ if not doc_type:
208
+ return None
209
+ from engine.core.rules.loader import list_available_types
210
+ known = list_available_types()
211
+ if doc_type not in known:
212
+ print(f" ⚠️ 警告: 未知公文类型「{doc_type}」,已回退使用通用规则"
213
+ f"(python -m gongwen list-types 查看 {len(known)} 类)")
214
+ return doc_type
215
+ return None
176
216
 
177
217
 
178
218
  def cmd_optimize(args):
@@ -199,6 +239,9 @@ def cmd_optimize(args):
199
239
  # 确定文档类型(共享辅助函数,优先 -t 参数,其次文件名推断)
200
240
  doc_type, type_source = _detect_doc_type(input_path, args.doc_type)
201
241
 
242
+ # V2.14:未知公文类型显式警告(拼错类型不再静默回退 common)
243
+ _warn_unknown_doc_type(doc_type)
244
+
202
245
  # 解析文档并检查
203
246
  model = parse_docx(str(input_path))
204
247
  issues = engine.check(model, doc_type)
@@ -232,6 +275,14 @@ def cmd_optimize(args):
232
275
  "verify_executed": False, "verify_passed": False,
233
276
  "verify_p0": None, "verify_p1": None, "verify_p2": None,
234
277
  "verify_error": None,
278
+ # V2.14:读取可见性(文本框/修订)——供 Agent 感知解析降级
279
+ "textboxes": len(model.textboxes),
280
+ "revisions": ({
281
+ "has": True,
282
+ "insert": model.revisions.insert_count,
283
+ "delete": model.revisions.delete_count,
284
+ "authors": model.revisions.authors,
285
+ } if model.revisions.has_revisions else None),
235
286
  }
236
287
 
237
288
  # === 预览信息(--json 时不打印人类文本)===
@@ -249,6 +300,8 @@ def cmd_optimize(args):
249
300
  print(f" - {i.name} @ {i.location}")
250
301
  if layout_parts:
251
302
  print(f"🎨 版式注入: {', '.join(layout_parts)}")
303
+ # V2.14:读取可见性提示(文本框/修订不静默忽略)
304
+ _print_read_visibility_hints(model)
252
305
 
253
306
  if not args.apply:
254
307
  if not is_json:
@@ -577,6 +577,9 @@ def _run_tracked_mode(args, changes, style_name, style_prompt, content_rules, do
577
577
  authors = sorted({s.author for s in suggestions})
578
578
  print(f" 审阅者: {', '.join(authors)}(可按审阅者筛选)")
579
579
  # S2 修复:审稿角色显示映射(默认 6 角色不再误判为 3 角色)
580
+ # V2.14 修复:reviewers_count 此前从未赋值(O10 重构遗留 NameError,
581
+ # 导致 tracked 模式生成文档后 rc=1)——从 args.reviewers 取(full 默认 6、quick 3)
582
+ reviewers_count = int(getattr(args, 'reviewers', 6) or 6)
580
583
  _role_display = {
581
584
  3: "精简版(3角色)",
582
585
  5: "完整版(5角色)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gongwen-skill",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "公文全流程处理专家 - GB/T 9704 格式检查/修复/内容优化/模板生成/版式注入",
5
5
  "type": "module",
6
6
  "main": "dsh/index.js",
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@deepseek-ai/cordis": ">=4",
49
- "@deepseek-ai/dsh-tools": ">=0.1.0",
49
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.3",
50
50
  "@deepseek-ai/schemastery": ">=3.18.0",
51
51
  "@deepseek-ai/dsh-client-ui-settings-plugins": ">=0.1.2-rc.1"
52
52
  },
@@ -201,7 +201,7 @@ python -m gongwen optimize 文件.docx -o 优化版.docx
201
201
  **Agent 响应**:
202
202
  ```
203
203
  📋 合规自检报告
204
- Skill 版本: v2.13.0
204
+ Skill 版本: v2.14.0
205
205
  路径判定: B(内容优化)
206
206
  依据: 用户提供纯文本+优化要求,无已有文档
207
207
  命令调用: 将原文保存为临时文件后执行 optimize-content --apply --paragraphs "1-3"
package/pyproject.toml CHANGED
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "gongwen-skill"
11
- version = "2.13.0"
11
+ version = "2.14.0"
12
12
  description = "公文全流程处理专家 - GB/T 9704 格式检查/修复/内容优化/模板生成/版式注入"
13
13
  readme = "README.md"
14
14
  license = {text = "MIT"}
@@ -501,6 +501,16 @@ check_rules:
501
501
  expected: true
502
502
  message: "整段加粗不符合公文规范,通常仅首句或点题词需要加粗"
503
503
 
504
+ # --- 文本框内容检查 (CHK-TBX001, V2.14) ---
505
+ # 公文红头/发文字号常承载于文本框(w:txbxContent);文本框存在但内容为空
506
+ # 说明红头区域有缺失。仅"检测到文本框"时触发,无文本框的文档不报。
507
+ - id: CHK-TBX001
508
+ name: "文本框内容检查"
509
+ severity: P2
510
+ field: header.textbox
511
+ expected: "文本框内容非空"
512
+ message: "检测到文本框但内容为空(红头/发文字号可能在文本框中缺失)"
513
+
504
514
  # --- 主送机关格式检查 (CHK-C026) ---
505
515
  - id: CHK-C026
506
516
  name: "主送机关格式检查"