feat: export core Hermes skills
This commit is contained in:
+110
@@ -0,0 +1,110 @@
|
||||
# Queue-Runner: Same-Name Different-Content File Silently Dropped (2026-07-08)
|
||||
|
||||
## Incident
|
||||
|
||||
邱律师 sent two versions of "2026年华新镇公立中小学生健康体检服务合同.docx" on the same day:
|
||||
- 11:05 BJT (27889 bytes): generic version without fee cap
|
||||
- 16:04 BJT (27482 bytes): specific version with 华新镇 in project name, ¥170,000 fee cap, different start date
|
||||
|
||||
Only the first was reviewed. The second was silently dropped.
|
||||
|
||||
## Root Cause Chain (3 components)
|
||||
|
||||
### 1. auto_notify manifest dedup (`grep -qFx`)
|
||||
|
||||
```bash
|
||||
# In auto_notify_new_file.sh:
|
||||
if ! grep -qFx "$orig_name" "$QUEUE_DIR/manifest.txt" 2>/dev/null; then
|
||||
echo "$orig_name" >> "$QUEUE_DIR/manifest.txt"
|
||||
fi
|
||||
```
|
||||
|
||||
The filename was already in manifest.txt from the first file → second file NOT appended → manifest has only ONE entry for this filename.
|
||||
|
||||
### 2. Runner single-pass no-backtrack
|
||||
|
||||
The runner reads manifest top-to-bottom in one pass. By 08:00:09 UTC it had already passed the 华新镇 line (first version was in done/ → "SKIP not found"). When auto_notify wrote the second file to queue/ at 08:04, the runner was already past that line processing later files. It never goes back.
|
||||
|
||||
### 3. done/ presence satisfies watchdog progress check
|
||||
|
||||
`[ -e "$QUEUE_DIR/done/$f" ]` — the first version in done/ counts as "complete" for this manifest line.
|
||||
|
||||
## Key Principle (Doro 2026-07-08 铁律)
|
||||
|
||||
**判断是否为相同文件不能只看文件名。** 必须检查合同实质内容:
|
||||
- 顾问单位(甲方)名称
|
||||
- 金额/费用上限
|
||||
- 合同期限(起止日期)
|
||||
- 项目内容描述
|
||||
- 字节大小
|
||||
|
||||
以上任何一项不同 → 视为新版本/不同合同,正常入队审查。
|
||||
全部相同 → 视为重复发送,可跳过。
|
||||
|
||||
## Fix Implemented (2026-07-09)
|
||||
|
||||
### 1. Content comparison script: `~/.hermes/scripts/contract_content_compare.py`
|
||||
|
||||
```
|
||||
Usage: python3 contract_content_compare.py <file_a> <file_b>
|
||||
Exit 0 = same content (duplicate)
|
||||
Exit 1 = different content (new version / different contract)
|
||||
Exit 2 = cannot read (treat as different, err on safe side)
|
||||
```
|
||||
|
||||
Compares:
|
||||
- File size (bytes)
|
||||
- 甲方 name (regex extraction from first 2000 chars)
|
||||
- All amounts (阿拉伯数字 ≥4 digits + 元/万, 人民币XXX, percentages)
|
||||
- All dates (YYYY年M月D日 format)
|
||||
- Project summary (first 500 chars normalized)
|
||||
|
||||
### 2. auto_notify_new_file.sh modification
|
||||
|
||||
Replaced the simple `grep -qFx` manifest dedup with content-level comparison:
|
||||
|
||||
```bash
|
||||
if grep -qFx "$orig_name" "$QUEUE_DIR/manifest.txt" 2>/dev/null; then
|
||||
# Same filename exists in manifest — compare content
|
||||
EXISTING="" # find in done/ or queue/
|
||||
COMPARE_RESULT=$(python3 contract_content_compare.py "$EXISTING" "$filepath")
|
||||
if [ $? -eq 0 ]; then
|
||||
# Content identical → true duplicate, skip
|
||||
log "SKIP duplicate (content identical): $orig_name"
|
||||
return
|
||||
else
|
||||
# Content different → new version, rename with timestamp suffix and queue
|
||||
RENAMED="${orig_name%.*}_v${TS}.${orig_name##*.}"
|
||||
cp "$filepath" "$QUEUE_DIR/$RENAMED"
|
||||
echo "$RENAMED" >> "$QUEUE_DIR/manifest.txt"
|
||||
log "SAME NAME DIFFERENT CONTENT — queued as new: $RENAMED"
|
||||
fi
|
||||
else
|
||||
# Brand new filename, normal flow
|
||||
cp "$filepath" "$QUEUE_DIR/${orig_name}"
|
||||
echo "$orig_name" >> "$QUEUE_DIR/manifest.txt"
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Verification
|
||||
|
||||
Tested with the actual 华新镇 two files:
|
||||
```
|
||||
$ python3 contract_content_compare.py file1.docx file2.docx
|
||||
DIFFERENT: 两份文件内容不同(新版本/不同合同)
|
||||
- 字节大小不同: 27889 vs 27482
|
||||
- 金额不同: A多set(), B多{'170000'}
|
||||
- 日期不同: A多{'2026年9月10日'}, B多{'2026年9月1日'}
|
||||
- 内容不同(第212字起): '...年公立中小学生健康检查...' vs '...年华新镇公立中小学生健康体检...'
|
||||
```
|
||||
|
||||
## Key Lesson
|
||||
|
||||
The initial diagnosis went through multiple wrong iterations:
|
||||
1. First said "queue-runner only checks filename" — wrong (tracker guard also exists)
|
||||
2. Then said "tracker guard is the one that skipped" — wrong (no tracker skip in logs)
|
||||
3. Then said "整个链路没有内容比对" — wrong (Doro corrected: the system should have had it)
|
||||
|
||||
**Correct diagnosis process**: trace the actual log timestamps precisely, verify each claim with tool output, don't assume mechanisms exist or don't exist without reading the actual code.
|
||||
|
||||
**Doro's requirement**: "不能用文件名判断是否为相同文件,需要查看合同内容(包括顾问单位名称、金额、日期等)以及字节大小,要全面判断。" This is a capability requirement, not just a bug fix — the system must understand what makes two contracts "the same" at a business level.
|
||||
Reference in New Issue
Block a user