[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6G28T3W2YGY1ZPXMHS1H9SD":3,"skill-same:01M6G28T3W2YGY1ZPXMHS1H9SD":53},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":24,"linkOnly":25,"markdownContent":26,"markdownBody":27,"frontMatter":28,"refName":30,"commitSha":31,"skillDirectory":32,"forksCount":33,"repositoryHtmlUrl":34,"repositoryHomepageUrl":6,"ownerHtmlUrl":35,"ownerBlogUrl":36,"ownerDescription":37,"updatedAt":38,"install":39,"resources":52},"01M6G28T3W2YGY1ZPXMHS1H9SD","content-hash-cache-pattern",null,"使用SHA-256内容哈希缓存昂贵的文件处理结果——路径无关、自动失效、服务层分离。","oabdelmaksoud\u002FAgention","oabdelmaksoud","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F50699149?v=4","01M6D5CVVN778ZCDP1WHS816SP","Omar Abdelmaksoud","01M6D8A4TE76V3DCSH3D94VG1V",2,"MIT","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-CN\u002Fskills\u002Fcontent-hash-cache-pattern\u002FSKILL.md",[],[19,20,21,22,23],"content","cache","pattern","content hash cache pattern","文件","2026-11-10 10:12:30",false,"---\nname: content-hash-cache-pattern\ndescription: 使用SHA-256内容哈希缓存昂贵的文件处理结果——路径无关、自动失效、服务层分离。\norigin: ECC\n---\n\n# 内容哈希文件缓存模式\n\n使用 SHA-256 内容哈希作为缓存键，缓存昂贵的文件处理结果（PDF 解析、文本提取、图像分析）。与基于路径的缓存不同，此方法在文件移动\u002F重命名后仍然有效，并在内容更改时自动失效。\n\n## 何时激活\n\n* 构建文件处理管道时（PDF、图像、文本提取）\n* 处理成本高且同一文件被重复处理时\n* 需要一个 `--cache\u002F--no-cache` CLI 选项时\n* 希望在不修改现有纯函数的情况下为其添加缓存时\n\n## 核心模式\n\n### 1. 基于内容哈希的缓存键\n\n使用文件内容（而非路径）作为缓存键：\n\n```python\nimport hashlib\nfrom pathlib import Path\n\n_HASH_CHUNK_SIZE = 65536  # 64KB chunks for large files\n\ndef compute_file_hash(path: Path) -> str:\n    \"\"\"SHA-256 of file contents (chunked for large files).\"\"\"\n    if not path.is_file():\n        raise FileNotFoundError(f\"File not found: {path}\")\n    sha256 = hashlib.sha256()\n    with open(path, \"rb\") as f:\n        while True:\n            chunk = f.read(_HASH_CHUNK_SIZE)\n            if not chunk:\n                break\n            sha256.update(chunk)\n    return sha256.hexdigest()\n```\n\n**为什么使用内容哈希？** 文件重命名\u002F移动 = 缓存命中。内容更改 = 自动失效。无需索引文件。\n\n### 2. 用于缓存条目的冻结数据类\n\n```python\nfrom dataclasses import dataclass\n\n@dataclass(frozen=True, slots=True)\nclass CacheEntry:\n    file_hash: str\n    source_path: str\n    document: ExtractedDocument  # The cached result\n```\n\n### 3. 基于文件的缓存存储\n\n每个缓存条目都存储为 `{hash}.json` —— 通过哈希实现 O(1) 查找，无需索引文件。\n\n```python\nimport json\nfrom typing import Any\n\ndef write_cache(cache_dir: Path, entry: CacheEntry) -> None:\n    cache_dir.mkdir(parents=True, exist_ok=True)\n    cache_file = cache_dir \u002F f\"{entry.file_hash}.json\"\n    data = serialize_entry(entry)\n    cache_file.write_text(json.dumps(data, ensure_ascii=False), encoding=\"utf-8\")\n\ndef read_cache(cache_dir: Path, file_hash: str) -> CacheEntry | None:\n    cache_file = cache_dir \u002F f\"{file_hash}.json\"\n    if not cache_file.is_file():\n        return None\n    try:\n        raw = cache_file.read_text(encoding=\"utf-8\")\n        data = json.loads(raw)\n        return deserialize_entry(data)\n    except (json.JSONDecodeError, ValueError, KeyError):\n        return None  # Treat corruption as cache miss\n```\n\n### 4. 服务层包装器（单一职责原则）\n\n保持处理函数的纯净性。将缓存作为一个单独的服务层添加。\n\n```python\ndef extract_with_cache(\n    file_path: Path,\n    *,\n    cache_enabled: bool = True,\n    cache_dir: Path = Path(\".cache\"),\n) -> ExtractedDocument:\n    \"\"\"Service layer: cache check -> extraction -> cache write.\"\"\"\n    if not cache_enabled:\n        return extract_text(file_path)  # Pure function, no cache knowledge\n\n    file_hash = compute_file_hash(file_path)\n\n    # Check cache\n    cached = read_cache(cache_dir, file_hash)\n    if cached is not None:\n        logger.info(\"Cache hit: %s (hash=%s)\", file_path.name, file_hash[:12])\n        return cached.document\n\n    # Cache miss -> extract -> store\n    logger.info(\"Cache miss: %s (hash=%s)\", file_path.name, file_hash[:12])\n    doc = extract_text(file_path)\n    entry = CacheEntry(file_hash=file_hash, source_path=str(file_path), document=doc)\n    write_cache(cache_dir, entry)\n    return doc\n```\n\n## 关键设计决策\n\n| 决策 | 理由 |\n|----------|-----------|\n| SHA-256 内容哈希 | 与路径无关，内容更改时自动失效 |\n| `{hash}.json` 文件命名 | O(1) 查找，无需索引文件 |\n| 服务层包装器 | 单一职责原则：提取功能保持纯净，缓存是独立的关注点 |\n| 手动 JSON 序列化 | 完全控制冻结数据类的序列化 |\n| 损坏时返回 `None` | 优雅降级，在下次运行时重新处理 |\n| `cache_dir.mkdir(parents=True)` | 在首次写入时惰性创建目录 |\n\n## 最佳实践\n\n* **哈希内容，而非路径** —— 路径会变，内容标识不变\n* 对大文件进行哈希时**分块处理** —— 避免将整个文件加载到内存中\n* **保持处理函数的纯净性** —— 它们不应了解任何关于缓存的信息\n* **记录缓存命中\u002F未命中**，并使用截断的哈希值以便调试\n* **优雅地处理损坏** —— 将无效的缓存条目视为未命中，永不崩溃\n\n## 应避免的反模式\n\n```python\n# BAD: Path-based caching (breaks on file move\u002Frename)\ncache = {\"\u002Fpath\u002Fto\u002Ffile.pdf\": result}\n\n# BAD: Adding cache logic inside the processing function (SRP violation)\ndef extract_text(path, *, cache_enabled=False, cache_dir=None):\n    if cache_enabled:  # Now this function has two responsibilities\n        ...\n\n# BAD: Using dataclasses.asdict() with nested frozen dataclasses\n# (can cause issues with complex nested types)\ndata = dataclasses.asdict(entry)  # Use manual serialization instead\n```\n\n## 适用场景\n\n* 文件处理管道（PDF 解析、OCR、文本提取、图像分析）\n* 受益于 `--cache\u002F--no-cache` 选项的 CLI 工具\n* 跨多次运行出现相同文件的批处理\n* 在不修改现有纯函数的情况下为其添加缓存\n\n## 不适用场景\n\n* 必须始终保持最新的数据（实时数据流）\n* 缓存条目可能极其庞大的情况（应考虑使用流式处理）\n* 结果依赖于文件内容之外参数的情况（例如，不同的提取配置）\n","# 内容哈希文件缓存模式\n\n使用 SHA-256 内容哈希作为缓存键，缓存昂贵的文件处理结果（PDF 解析、文本提取、图像分析）。与基于路径的缓存不同，此方法在文件移动\u002F重命名后仍然有效，并在内容更改时自动失效。\n\n## 何时激活\n\n* 构建文件处理管道时（PDF、图像、文本提取）\n* 处理成本高且同一文件被重复处理时\n* 需要一个 `--cache\u002F--no-cache` CLI 选项时\n* 希望在不修改现有纯函数的情况下为其添加缓存时\n\n## 核心模式\n\n### 1. 基于内容哈希的缓存键\n\n使用文件内容（而非路径）作为缓存键：\n\n```python\nimport hashlib\nfrom pathlib import Path\n\n_HASH_CHUNK_SIZE = 65536  # 64KB chunks for large files\n\ndef compute_file_hash(path: Path) -> str:\n    \"\"\"SHA-256 of file contents (chunked for large files).\"\"\"\n    if not path.is_file():\n        raise FileNotFoundError(f\"File not found: {path}\")\n    sha256 = hashlib.sha256()\n    with open(path, \"rb\") as f:\n        while True:\n            chunk = f.read(_HASH_CHUNK_SIZE)\n            if not chunk:\n                break\n            sha256.update(chunk)\n    return sha256.hexdigest()\n```\n\n**为什么使用内容哈希？** 文件重命名\u002F移动 = 缓存命中。内容更改 = 自动失效。无需索引文件。\n\n### 2. 用于缓存条目的冻结数据类\n\n```python\nfrom dataclasses import dataclass\n\n@dataclass(frozen=True, slots=True)\nclass CacheEntry:\n    file_hash: str\n    source_path: str\n    document: ExtractedDocument  # The cached result\n```\n\n### 3. 基于文件的缓存存储\n\n每个缓存条目都存储为 `{hash}.json` —— 通过哈希实现 O(1) 查找，无需索引文件。\n\n```python\nimport json\nfrom typing import Any\n\ndef write_cache(cache_dir: Path, entry: CacheEntry) -> None:\n    cache_dir.mkdir(parents=True, exist_ok=True)\n    cache_file = cache_dir \u002F f\"{entry.file_hash}.json\"\n    data = serialize_entry(entry)\n    cache_file.write_text(json.dumps(data, ensure_ascii=False), encoding=\"utf-8\")\n\ndef read_cache(cache_dir: Path, file_hash: str) -> CacheEntry | None:\n    cache_file = cache_dir \u002F f\"{file_hash}.json\"\n    if not cache_file.is_file():\n        return None\n    try:\n        raw = cache_file.read_text(encoding=\"utf-8\")\n        data = json.loads(raw)\n        return deserialize_entry(data)\n    except (json.JSONDecodeError, ValueError, KeyError):\n        return None  # Treat corruption as cache miss\n```\n\n### 4. 服务层包装器（单一职责原则）\n\n保持处理函数的纯净性。将缓存作为一个单独的服务层添加。\n\n```python\ndef extract_with_cache(\n    file_path: Path,\n    *,\n    cache_enabled: bool = True,\n    cache_dir: Path = Path(\".cache\"),\n) -> ExtractedDocument:\n    \"\"\"Service layer: cache check -> extraction -> cache write.\"\"\"\n    if not cache_enabled:\n        return extract_text(file_path)  # Pure function, no cache knowledge\n\n    file_hash = compute_file_hash(file_path)\n\n    # Check cache\n    cached = read_cache(cache_dir, file_hash)\n    if cached is not None:\n        logger.info(\"Cache hit: %s (hash=%s)\", file_path.name, file_hash[:12])\n        return cached.document\n\n    # Cache miss -> extract -> store\n    logger.info(\"Cache miss: %s (hash=%s)\", file_path.name, file_hash[:12])\n    doc = extract_text(file_path)\n    entry = CacheEntry(file_hash=file_hash, source_path=str(file_path), document=doc)\n    write_cache(cache_dir, entry)\n    return doc\n```\n\n## 关键设计决策\n\n| 决策 | 理由 |\n|----------|-----------|\n| SHA-256 内容哈希 | 与路径无关，内容更改时自动失效 |\n| `{hash}.json` 文件命名 | O(1) 查找，无需索引文件 |\n| 服务层包装器 | 单一职责原则：提取功能保持纯净，缓存是独立的关注点 |\n| 手动 JSON 序列化 | 完全控制冻结数据类的序列化 |\n| 损坏时返回 `None` | 优雅降级，在下次运行时重新处理 |\n| `cache_dir.mkdir(parents=True)` | 在首次写入时惰性创建目录 |\n\n## 最佳实践\n\n* **哈希内容，而非路径** —— 路径会变，内容标识不变\n* 对大文件进行哈希时**分块处理** —— 避免将整个文件加载到内存中\n* **保持处理函数的纯净性** —— 它们不应了解任何关于缓存的信息\n* **记录缓存命中\u002F未命中**，并使用截断的哈希值以便调试\n* **优雅地处理损坏** —— 将无效的缓存条目视为未命中，永不崩溃\n\n## 应避免的反模式\n\n```python\n# BAD: Path-based caching (breaks on file move\u002Frename)\ncache = {\"\u002Fpath\u002Fto\u002Ffile.pdf\": result}\n\n# BAD: Adding cache logic inside the processing function (SRP violation)\ndef extract_text(path, *, cache_enabled=False, cache_dir=None):\n    if cache_enabled:  # Now this function has two responsibilities\n        ...\n\n# BAD: Using dataclasses.asdict() with nested frozen dataclasses\n# (can cause issues with complex nested types)\ndata = dataclasses.asdict(entry)  # Use manual serialization instead\n```\n\n## 适用场景\n\n* 文件处理管道（PDF 解析、OCR、文本提取、图像分析）\n* 受益于 `--cache\u002F--no-cache` 选项的 CLI 工具\n* 跨多次运行出现相同文件的批处理\n* 在不修改现有纯函数的情况下为其添加缓存\n\n## 不适用场景\n\n* 必须始终保持最新的数据（实时数据流）\n* 缓存条目可能极其庞大的情况（应考虑使用流式处理）\n* 结果依赖于文件内容之外参数的情况（例如，不同的提取配置）\n",{"name":5,"origin":29,"description":7},"ECC","main","a318f48de3c5718e8ea2e9f6fae7790e8a759e85","upstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-CN\u002Fskills\u002Fcontent-hash-cache-pattern",0,"https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fo-abdelmaksoud\u002F","Full-Stack Engineer | AI Systems Architect | Building autonomous multi-agent systems","2026-03-08 21:23:03",{"source":8,"skillName":5,"commands":40,"prompt":50,"zipAvailable":51},[41,44,47],{"tool":42,"command":43},"npx","npx skills add oabdelmaksoud\u002FAgention --skill content-hash-cache-pattern",{"tool":45,"command":46},"bunx","bunx skills add oabdelmaksoud\u002FAgention --skill content-hash-cache-pattern",{"tool":48,"command":49},"pnpm","pnpm dlx skills add oabdelmaksoud\u002FAgention --skill content-hash-cache-pattern","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fdocs\u002Fzh-CN\u002Fskills\u002Fcontent-hash-cache-pattern\u002FSKILL.md",true,[],[54,78,92,125,151,171],{"skillNo":55,"name":56,"nameZh":6,"description":57,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":58,"categories":59,"keywords":65,"publishedAt":24},"01M6G2QFCBNBYAJF2KTK85G9A6","visa-doc-translate","Translate visa application documents (images) to English and create a bilingual PDF with original and translation","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fvisa-doc-translate\u002FSKILL.md",[60],{"categoryNo":61,"categoryName":62,"taxonomyType":63,"taxonomyTypeDesc":64},"01JBSEEDCAT000000000000002","文档处理","SCENARIO","使用场景",[66,67,68,69,70,71,72,73,74,75,76,77],"translate","doc","visa doc translate","bilingual","with","english","application","PDF","translation","documents","create","images",{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":24},"01M6G2QB09TSK6BY4ME5X20EVQ","verification-loop","A comprehensive verification system for Claude Code sessions.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[85,86,87,88,89,90,91],"verification","loop","verification loop","sessions","code","claude code sessions","system",{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":96,"categories":97,"keywords":109,"publishedAt":24},"01M6G2Q6V2F7G03VAAF27FXPJR","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[98,101,104],{"categoryNo":99,"categoryName":100,"taxonomyType":63,"taxonomyTypeDesc":64},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":102,"categoryName":103,"taxonomyType":63,"taxonomyTypeDesc":64},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":105,"categoryName":106,"taxonomyType":107,"taxonomyTypeDesc":108},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[110,111,112,113,114,115,116,117,118,89,119,120,121,122,70,123,124],"workflow","tdd","tdd workflow","use","unit","coverage","refactoring","e2e","integration","development","e2e tests","tests","driven","test","writing",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":24},"01M6G2Q359YJRWAR2PFCEQAXF3","swiftui-patterns","SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS\u002FmacOS UI best practices.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswiftui-patterns\u002FSKILL.md",[],[132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,70],"patterns","swiftui","swiftui patterns","architecture","macos","performance","state management","best practices","state","ui","Optimization","ios","architecture patterns","Composition","performance optimization","view","management","swiftui architecture","navigation",{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":158,"publishedAt":24},"01M6G2PY8B2FWZTWPZ84H83Y7C","swift-protocol-di-testing","Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-protocol-di-testing\u002FSKILL.md",[157],{"categoryNo":99,"categoryName":100,"taxonomyType":63,"taxonomyTypeDesc":64},[159,160,161,162,89,163,164,165,166,91,167,168,169,170],"swift protocol di testing","protocol","swift","testing","protocols","file","network","injection","dependency","swift testing","dependency injection","mock",{"skillNo":172,"name":173,"nameZh":6,"description":174,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":175,"categories":176,"keywords":177,"publishedAt":24},"01M6G2PSCN2GXV9FFZDRRRWVB6","swift-concurrency-6-2","Swift 6.2 Approachable Concurrency — single-threaded by default, @concurrent for explicit background offloading, isolated conformances for main actor types.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FAgention\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-concurrency-6-2\u002FSKILL.md",[],[178,179,180,161,181,30,182],"concurrency","swift concurrency","swift concurrency 6 2","default","types"]